Hot questions for Using Joda-Time in java time

Question:

I have an instance of Instant (org.joda.time.Instant) which I get in some api response. I have another instance from (java.time.Instant) which I get from some other call. Now, I want to compare these two object to check which one get the latest one. How would it be possible?


Answer:

getMillis() from joda.time can be compared to toEpochMilli() from java.time.

Class documentation:

Example code.

java.time.Instant myJavaInstant = 
    java.time.Instant.ofEpochMilli( myJodaInstant.getMillis() ) ;

Going the other way.

// Caution: Loss of data if the java.time.Instant has microsecond
// or nanosecond fraction of second.
org.joda.time.Instant myJodaInstant = 
    new org.joda.time.Instant( myJavaInstant.toEpochMilli() ); 

Question:

I have a data source with joda time DateTime objects stored. I need to convert them into java ZonedDateTime objects, keeping the original timezone.

It is not sufficient to keep the offset since some DateTime objects represents daily repetitive tasks, and these tasks must occur at a specific time in a specific time zone for every date. They must thus follow the specified TimeZone transitions for example summer and winter time. I cannot tell the final usage of the DateTime objects, so I need to keep the Time Zone information on all objects to be safe.

How to convert from org.joda.time.DateTime to java.time.ZonedDateTime?

Will all

ord.joda.time.DateTimeZone.getId()

map to the id's available in

java.time.ZoneId


Answer:

Not all time-zone strings from Joda-Time will match java.time but the vast majority will as they are both based on the IANA tz data. Compare DateTimeZone.getAvailableIDs() to ZoneId.getAvailableZoneIds() to determine the mismatch. Additional identifiers can be mapped using ZoneId.of(String, Map).

To do the main conversion in the most efficient way, you have to pass in each field:

ZonedDateTime zdt = ZonedDateTime.ofLocal(
    LocalDateTime.of(
        dt.getYear(),
        dt.getMonthOfYear(),
        dt.getDayOfMonth(),
        dt.getHourOfDay(),
        dt.getMinuteOfHour(),
        dt.getSecondOfMinute(),
        dt.getMillisOfSecond() * 1_000_000),
    ZoneId.of(dt.getZone().getID(), ZoneId.SHORT_IDS),
    ZoneOffset.ofTotalSeconds(dt.getZone().getOffset(dt) / 1000));

Note the use of ZoneId.SHORT_IDS as the Map in this case.

For a simpler solution that handles most use cases, but at lower performance, use this:

ZonedDateTime zdt = dt.toGregorianCalendar().toZonedDateTime();

Question:

I have the following joda date parser:

ISODateTimeFormat.dateTimeParser().withOffsetParsed().

I'd like to refactor this to java.time api. But what is the exact equivalent to the parser above, especially regarding the offset?


Answer:

The best equivalent should be this constant in package java.time.format which prefers the parsed offset according to the documentation (like the behaviour when Joda-withOffsetParsed() is used):

DateTimeFormatter.ISO_OFFSET_DATE_TIME

However, there are still small differences. The decimal separator must be a dot in Java-8 (comma not tolerated although valid and even recommended in ISO-paper). Also: Java-8 manages nanosecond precision in contrast to Jodas millisecond precision. And maybe most important difference: If the offset is missing in your input then Java-8 throws an exception but Joda not (and applies the default time zone).

About choice of type: Since you are working with DateTime and fixed offsets the best equivalent should be here OffsetDateTime in Java-8. Example of migration:

DateTime dt = ISODateTimeFormat.dateTimeParser().withOffsetParsed().parseDateTime(input);

=>

OffsetDateTime odt = OffsetDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME); 

Question:

How do we calculate previous Sunday or previous to previous Sunday or in general lets say how to find out sunday prior to n weeks? The catch is if today is Sunday then it should return today as Sunday and not last week.

Looking for Joda-Time or Java 8 time solution.

Edit: I tried

DateTime sunday = now
    .minusWeeks(1)
    .withDayOfWeek(DateTimeConstants.SUNDAY)
    .wi‌​thTimeAtStartOfDay()‌​;
DateTime previousWeekSunday = now
    .minusWeeks(2)
    .withDayOfWeek(DateTimeConstants.SATURDAY)
    .‌​withTime(23, 59, 59, 999); 

but if current is Sunday then this logic fails as it does not give today's date.


Answer:

You basically need to check if today is Sunday, if not, then look back for the previous one...(or recursively move back the date if you need the previous one to that...)

Using java 8 you will need:


LocalDate date = LocalDate.now();
DayOfWeek todayAsDayOfWeek = date.getDayOfWeek();
LocalDate prevSun = todayAsDayOfWeek == DayOfWeek.SUNDAY ? date : date.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));
System.out.println(prevSun);

Edit: previousOrSame method will skip the check of the actual dayof the week

    LocalDate date = LocalDate.now();
    LocalDate prevSun = date.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));

    prevSun = date.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
    System.out.println(prevSun);

Question:

I am having trouble using Joda daysBetween function. It keeps telling me

The method daysBetween(ReadableInstant, ReadableInstant) in the type Days is not applicable for the arguments (LocalDate, LocalDate)

when I try to insert two localdate items.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);
        LocalDate date = LocalDate.parse(reviewDate, formatter);
        Date dateNow = new Date();
        LocalDate date1 = LocalDate.parse(dateNow.toString(),formatter);
        int days = Days.daysBetween(date,date1).getDays();

I am trying to get the number of days between reviewDate and the current date date1 what m I doing wrong?


Answer:

You speak about Joda-Time-class org.joda.time.LocalDate. Of course, the expression Days.daysBetween(ReadablePartial,ReadablePartial) can process such an input without problems, but you have a problem?! This has given me the idea that your imports might be wrong. And indeed:

You also use this expression:

DateTimeFormatter.ofPattern("MMMM d, yyyy", Locale.ENGLISH);

But that code is not Joda-code, it is Java-8-code. So you obviously mix-up the different classes org.joda.time.LocalDate with java.time.LocalDate. And that is what your compiler is complaining about. Don't mix both libraries. They are not compatible, and the partially equal names will not help, too but can increase confusion.

Solution: Abandon Joda-Time completely since you are using Java-8. Instead of Days.daysBetween(...) you can use:

long days = ChronoUnit.DAYS.between(date, date1);

Question:

java.sql.Date date = java.sql.Date.valueOf("1900-01-01");
org.joda.time.LocalDate localDate = new org.joda.time.LocalDate(date);

Based above code, I did some tests as below:

  • Question #1 why do I get different localDate object with same timezone?

If I change local timezone to UTC+8 Singapore Timezone, will get 1899-12-31

If I change local timezone to UTC+8 China Timezone, will get 1900-01-01

  • Question #2 why do I get same time with different timezone?

If I change local timezone to UTC-8 America/Los_Angeles Timezone, will get 1900-01-01

If I change local timezone to UTC+8 China Timezone, will get 1900-01-01

Could someone help clarify that?? it is little bit confused.


Answer:

In 1900, Singpore's offset is UTC +6:55:25, so when you create date 1900-01-01 in Singapore time zone, it should be 1899-12-31T17:04:35Z[UTC] as below:

java.time.ZonedDateTime localDateTime = ZonedDateTime.of(1900, 01, 01, 0,
            0, 0, 0, ZoneId.of("Singapore"));

System.out.println(localDateTime.withZoneSameInstant(ZoneId.of("UTC")));
// 1899-12-31T17:04:35Z[UTC]

However, when you use java.sql.Date, it use wrong offset UTC +08:00:

TimeZone.setDefault(TimeZone.getTimeZone("Singapore"));
java.sql.Date date = java.sql.Date.valueOf("1900-01-01");

java.time.Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println(instant);   // 1899-12-31T16:00:00Z

and when you create org.joda.time.LocalDateTime with this wrong value, Joda use UTC +6:55:25 as offset, resulting in a date time 1899-12-31T16:00:00 + 6:55:25:

org.joda.time.LocalDateTime singaporeDateTime = new org.joda.time.LocalDateTime(date);
System.out.println(singaporeDateTime);  // 1899-12-31T22:55:25.000 

You can use the similar approach to check the result of Shanghai and Los Angelas, the point is, avoid using java.sql.Date and other deprecated date time related classes. Use java.time instead if you are working with java8 or higher.

Question:

This is my code to calculate deference time with joda time:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.joda.time.Interval;
import org.joda.time.Period;

public class DateDiff {

    public static void main(String[] args) {

    DateDiff obj = new DateDiff();
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-DD hh:mm:ss");

    try {

        Date date1 = simpleDateFormat.parse("2015-10-01 20:32:06");
        Date date2 = simpleDateFormat.parse("2015-10-25 00:52:36");

        obj.printDifference(date1, date2);  

        } catch (ParseException e) {
        }
    }

    public void printDifference(Date startDate, Date endDate){

        Interval interval = new Interval(startDate.getTime(), endDate.getTime());
        Period period = interval.toPeriod();

        System.out.printf(
            "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
            period.getYears(), period.getMonths(), period.getDays(),
            period.getHours(), period.getMinutes(), period.getSeconds());
    }
}

Here is my reference : http://www.mkyong.com/java/java-time-elapsed-in-days-hours-minutes-seconds/ When I run the code I received:

0 years, 0 months, 2 days, 4 hours, 20 minutes, 30 seconds

Can somebody tell me whats wrong with my code?


Answer:

I've changed the 'DD'to 'dd' but the result remains the same

Well, this is because you ignore something of your Period instance: the weeks.

You need to output the instance like this:

System.out.printf(
    "%d years, %d months, %d weeks, %d days, %d hours, %d minutes, %d seconds%n",
    period.getYears(), period.getMonths(), period.getWeeks(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());

And you will get:

0 years, 0 months, 3 weeks, 2 days, 4 hours, 20 minutes, 30 seconds

and as far as I can see it ... it looks correct.


If you don't like to use the weeks here, then you can use a different PeriodType. For example:

Period period = interval.toPeriod(PeriodType.yearMonthDayTime());

This creates a type which just uses the year, month, day and the time, like you want in your example.

The output is then:

0 years, 0 months, 23 days, 4 hours, 20 minutes, 30 seconds

Question:

Some businesses track events in time by "hour ending". Each hour of the day is represented by an ordinal number:

  • 1…24 for UTC
  • 1…23, 1…24, and 1…25 for time zones with a one-hour Daylight Saving Time (DST) adjustment.

So first hour of day, from midnight to 01:00 is Hour Ending 01.

To me, it seems like a silly way to track time. More sensible would be using time-of-day by the Half-Open approach, [), where the beginning is inclusive, and ending is exclusive. So:

  • 2014-12-05T01:00:00.000 would mark Hour Ending 01
  • 2014-12-06T00:00:00.000 (midnight) would mark Hour Ending 24.

Indeed, that is what I want to store in my database (Postgres), a TIMESTAMP WITH TIME ZONE value converted from the date & ordinal hour number. So my question is:

Given a date and an ordinal "Hour Ending" number (1…23/24/25 for locality with 1-hour DST), how do I convert to a date-time value?

I'm familiar with Joda-Time and java.time. Does either of them offer a way to convert? If not, what kind of algorithm handles both the ordinal number conversion and DST?

Or should I not fight this, and just store the local date as a string with a suffix of the ordinal hour number?


Answer:

Perhaps the java.time method you are looking for is truncatedTo, which can be used to take any ZonedDateTime and truncate the minutes and seconds

ZonedDateTime zdt = ZonedDateTime.now();
ZonedDateTime rounded = zdt.truncatedTo(ChronoUnit.HOURS);
ZonedDateTime hourEnd = rounded.plusHours(1);

Question:

I want to convert a string like the following to an object that can evaluate an instant to be withing a periodic interval or not:

Mon: 0800-1300

I am looking for some kind of functionality that I could use similar to this pseudocode:

class IntervalHolder {

    private PeriodicInterval interval;

    public IntervalHolder(String intervalString) {
        interval = Interval.parse(intervalString)
    }

    public boolean isWithinInterval(Instant instant) {
        return interval.contains(instant);
    }

Interval from Yoda time seems "to work only once" in that case, because an instant also always specifies the date. Is there a class in the framework that would work for checking weekly intervals?


Answer:

There is no such option in Joda Time because all the relevant classes would either contain full information about time boundaries (that is the case with Duration and Interval) or would store a period in given unit (that is the case with Period).

I would recommend simply (of course with exporting all the constants to separate variables):

public boolean isWithinInterval(Instant instant) {
    DateTime dateTime = instant.toDateTime();
    return dateTime.getDayOfWeek() == MONDAY
           && dateTime.getHourOfDay() >= 8
           && dateTime.getHourOfDay() <= 13;

Note that you could of course create separate Duration and Period objects and use both of them in the comparison but I don't think this would be cleaner than the presented solution.

Question:

I'm using the ACTION_TIMEZONE_CHANGED intent filter on Android to respond to a timezone change.

I noticed that Jodas current timezone is not updated at this time using: DateTimeZone.getDefault()

When I use Java's default TimeZone.getDefault(), the timezone is correct.

Notice: When I change it again: Joda has the value I changed it to before. So it is behind (not yet updated when Android fires the Broadcast Intent).

So I only can use the Java timezone for current timezone. But my domain object uses Joda DateTimeZone`s. Now I want to compare current timezone with the one in my domain object. Is it save to do this:

TimeZone currenTimeZone = TimeZone.getDefault();
if(action.getLocation().getDateTimeZone().getID().equals(currenTimeZone.getID()))) {
 [...]
}

? Or can the timezone ids differ between the two libraries?


Answer:

tl;dr

No, not safe to assume a time zone:

  • exists.
  • has a particular identifier defined.
  • has the same definition/rules.
tzdata

Most operating systems and software libraries rely on the tz database maintained by IANA to supply current and past time zone information. Also known as tzdata or TZDB. Formerly known as the Olson Database.

Frequent changes

Around the world, politicians enjoy frequently changing, redefining, rescheduling, renaming, and otherwise messing around with time zone definitions and rules. They often do so with little forewarning, such as less that two months now in Turkey (autumn of 2016).

Sometimes new time zones are defined. So in that regard, to answer your Question specifically: Yes, some copies of tzdata may have newer time zone definitions that do not exist in older copies, so there may a difference of time zone identifiers.

Also, new names are sometimes given to existing time zones. For example, with India recently restoring their city names, Asia/Calcutta is now also labeled as Asia/Kolkota. Again, old tzdata copies will not know of this newer name.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

Some software will extend the tzdata to try to recognize these pseudo-time zones. Not a good idea. But, again, this means using these non-standard time zone identifiers might work in one place but not another. Stick with the official time zone names.

Some zones have a display name, such as British Time. But you should never use that as an identifier.

Updating

System administrators must make the effort to update the tzdata in all the various places it might be used:

  • Operating system
  • Java Virtual Machine
  • Software libraries (such as Joda-Time, and possibly ThreeTen-Backport).

Providers of JVMs usually include a recent version of the tzdata in updates to the JVMs. But politicians twiddle with time zones more often than Java updates. So you may need to manually update the JVM. Oracle provides the Timezone Update Tool for Oracle & OpenJDK JVMs.

Joda-Time includes its own copy of tzdata. So you will need to either update your Joda-Time library or do a manual replacement of the tzdata. Note that the Joda-Time project is now in maintenance-mode, and advises moving to the java.time classes bundled with Java 8 and later.

List known identifiers

The java.time classes can show you a list of their known zone identifiers.

Set<String> zoneIds = ZoneId.getAvailableZoneIds() ;

Other libraries and operating systems may be able to do the same.

Avoid legacy date-time classes

The troublesome old date-time classes bundled with the earliest versions of Java are now legacy, supplanted by the java.time classes.

So your use of TimeZone.getDefault() is now outmoded by ZoneId.systemDefault:

ZoneId z = ZoneId.systemDefault() ;
String zoneIdentifier = z.toString() ;

Using that to get current moment in a particular zone.

ZonedDateTime zdt = ZonedDateTime.now( z );

Question:

I am struggling to get the unix time epoch with microseconds in this format(1586420933.453254). I tried different classes.

- java.utils.Calendar
- java.time.Instant
- org.joda.time.DateTime

But I am getting only milliseconds like this - 1586420933453

How do I get the unix epoch with microseconds like this 1586420933.453254 in Java.


Answer:

You can easily do it using standard java time Instant + a number format. Keep in mind the result will be in UTC, though. Here is a draft with current time:

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.time.Instant;


Instant datetime = Instant.now();

// Extract needed information: date time as seconds + fraction of that second
long secondsFromEpoch = datetime.getEpochSecond();
int nanoFromBeginningOfSecond = datetime.getNano();
double nanoAsFraction = datetime.getNano()/1e9;

// Now, let's put that as text
double epochSecondUTCPlusNano = secondsFromEpoch + nanoAsFraction;
NumberFormat format = DecimalFormat.getInstance();
format.setMinimumFractionDigits(6);
format.setMaximumFractionDigits(6);
format.setGroupingUsed(false);
System.out.print(format.format(epochSecondUTCPlusNano));