Hot questions for Using Joda-Time in datetime format

Top Java Programmings / Joda-Time / datetime format

Question:

I tried different ISODateTimeFormats (dateHourMinuteSecond(), dateTimeNoMillis()) and my own format "yyyy-MM-dd'T'HH:mm:ss", to get time stamp be parsed to date time object without milliseconds, it failed.

For each format I tried to modify the string accordingly:

String value = "2011-01-24T09:45:00.000";
DateTimeFormatter formatter = ISODateTimeFormat.dateHourMinuteSecond();
value = value.substring(0, value.lastIndexOf('.'));
System.out.println("Formatted dateTime: "+formatter.parseDateTime(value));

Output:

Formatted dateTime: 2011-01-24T09:45:00.000Z

Answer:

I did my tests in jodatime 2.2.

formatter.parseDateTime(value) returns a DateTime object. When you pass this object to System.out.println, it calls the toString() method of this DateTime object. And taking a look at the source code, I found out that it calls ISODateTimeFormat:

// (from jodatime source)
/**
 * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).
 * 
 * @return ISO8601 time formatted string.
 */
@ToString
public String toString() {
    return ISODateTimeFormat.dateTime().print(this);
}

To get the output you want (without milliseconds), you need to format the DateTime object:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
value = value.substring(0, value.lastIndexOf('.'));
DateTime datetime = formatter.parseDateTime(value);

// *** create the formatter with the "no-millis" format ***
DateTimeFormatter formatterNoMillis = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");
System.out.println("Formatted dateTime: " + datetime.toString(formatterNoMillis));

The output will be:

Formatted dateTime: 2011-01-24T09:45:00

You could also do:

System.out.println("Formatted dateTime: " + formatterNoMillis.print(datetime));
//the output will be the same

Question:

I have the next string: 2000-01-01T01:01:01 and 2000-01-01T01:01:01.000Z Is it possible use ISODateTimeFormat for parse both dates?


Answer:

You can use dateTimeParser(). Its description promises:

It accepts formats described by the following syntax: 
 datetime          = time | date-opt-time
 time              = 'T' time-element [offset]
 date-opt-time     = date-element ['T' [time-element] [offset]]
 date-element      = std-date-element | ord-date-element | week-date-element
 std-date-element  = yyyy ['-' MM ['-' dd]]
 ord-date-element  = yyyy ['-' DDD]
 week-date-element = xxxx '-W' ww ['-' e]
 time-element      = HH [minute-element] | [fraction]
 minute-element    = ':' mm [second-element] | [fraction]
 second-element    = ':' ss [fraction]
 fraction          = ('.' | ',') digit+
 offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])

Test:

    String s1 = "2000-01-01T01:01:01.000Z";
    String s2 = "2000-01-01T01:01:01";

    DateTime dt1 = ISODateTimeFormat.dateTimeParser().withOffsetParsed().parseDateTime(s1);
    System.out.println(dt1); // 2000-01-01T01:01:01.000Z

    DateTime dt2 = ISODateTimeFormat.dateTimeParser().withOffsetParsed().parseDateTime(s2);
    System.out.println(dt2); // 2000-01-01T01:01:01.000+01:00 (using default zone)

Of course, the string without offset is somehow dubious. YOU decide how to interprete the result resp. in which time zone because this information is missing in some parts of your text input.

Personally, I wished Joda-Time offers a possibility to give preference to parsed offset information, but choosing a user-defined time zone offset in case the text input does not have an offset (Joda-Time only allows to set a user-defined zone via formatter.withZone(...) which will be preferred to any available offset information in text input - not ideal).

Question:

I have some HR records whose dates are formatted as dd/MM/yy, and I am normalizing them to dd-MM-yyyy using Joda-Time. So for example, the following records are normalized as follows

  Input        Output
30/01/14 --> 30-01-2014
15/07/99 --> 15-07-1999
24/03/84 --> 24-03-1984

Based on various criteria (average length of human lifespan, when company has been around, ... ), I can assume what year 99 might refer to.

However, if I wanted to specify that 99 refers to 1899 or some other year ending in 99, how would I do this?

I am reading over the docs for the DateTimeFormatter patterns, as well as the explanations here, and it looks like CenturyOfEra field C might be what I want to use, but it isn't obvious how I would use it.


Answer:

If I understand the question correctly, it is referred as "Pivot Year": http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormatter.html#withPivotYear%28int%29

The CenturyOfEra is just our current century - XXI, the one which so many sci-fi authors dreamed about few decades back.

Question:

Using SuperCSV I am utilizing the ParseLocalDate cell processor for Joda time:

private static CellProcessor[] processors = new CellProcessor[] {
    new Optional(new ParseLocalDate(DateTimeFormat.forPattern("MM/dd/yyyy")))
};

This works great. However, in addition to accepting a MM/dd/yyyy format, I would also like to accept yyyy-MM-dd, but I have been unable to figure out how to provide two distinct cell processors to handle the same field. I tried chaining them but that didn't work. Any idea how I can get it to accept both formats?


Answer:

Ended up figuring it out, you can define a custom cell processor and process as many date formats as you like:

public class ParseLocalDate extends CellProcessorAdaptor {

    public ParseLocalDate() {
        super();
    }

    public ParseLocalDate(CellProcessor next) {
        super(next);
    }

    @Override
    public Object execute(Object value, CsvContext context) {
        validateInputNotNull(value, context);

        DateTimeFormatter[] dateFormats = {
            DateTimeFormat.forPattern("yyyy-MM-dd"),
            DateTimeFormat.forPattern("MM/dd/yyyy") };

        LocalDate date = null;
        for (DateTimeFormatter dtf : dateFormats) {
            try {
                date = LocalDate.parse(value.toString(), dtf);
                break;
            } catch (Exception e) {
                // was not able to be parsed with this format, do nothing
            }
        }

        if (date == null)       
            throw new SuperCsvCellProcessorException("Date could not be parsed", context, this);

        return date;
    }
}

Question:

I am having difficulty using JodaTime to handle Daylight savings time.

 String time = "3:45-PM";   
 DateTimeFormatter formatter = DateTimeFormat.forPattern("KK:mm-a");
 DateTime dt = formatter.parseDateTime(time).withZone(DateTimeZone.forID("America/New_York"));
 dt = dt.toDateTime(DateTimeZone.UTC);

 startDate = startDate.withHourOfDay(dt.getHourOfDay()).withMinuteOfHour(dt.getMinuteOfHour());

Output from this code snippet ends up being:

2015-04-08 16:46:51.952  INFO 12244 --- [nio-8080-exec-1] VALUES PULLED                        : 03:45-PM
2015-04-08 16:46:51.952  INFO 12244 --- [nio-8080-exec-1] VALUES PULLED                        : 08:45-PM

Currently, the time is 5 hours off. Which is not handling Daylights saving time. How do I get Joda Time to take DLS into account?


Answer:

This happens because the DateTime object that you get after parsing is set to the date 01-01-1970. It looks like you expect that it would be set to today, but it isn't.

If you want the time to be interpreted as 3:45 PM today in the timezone America/New_York, do this:

String time = "3:45-PM";

DateTimeFormatter formatter = DateTimeFormat.forPattern("KK:mm-a")
        .withZone(DateTimeZone.forID("America/New_York"));

DateTime dt = formatter.parseDateTime(time)
        .withDate(LocalDate.now());

System.out.println(dt);

System.out.println(dt.withZone(DateTimeZone.UTC));

Note: You need to set the zone on the DateTimeFormatter.

Question:

Im trying to create DBF file in FoxPro spec, but idk how to insert date. I dont know how to convert java Date to this:

FoxPro's field is 2 32bit integers: one stores the date, the other stores the time, stored in reverse byte order. The date integer stores the number of days from 1/1/4712BC. The time integer stores the number of milliseconds from 00:00:00.

Its easy to get days and milliseconds with JodaTime:

         DateTime start = new DateTime(-4713, 1, 1, 0, 0, 0, 0);
         DateTime end = new DateTime(2014, 1, 1, 0, 0, 0, 0);
         Days days = Days.daysBetween(start, end);
         long millis = end.getMillisOfDay();

but how to convert this info to needed format? For input a date I just use:

SimpleDateFormat simpledateformat = new SimpleDateFormat("yyyyMMdd");
simpledateformat.format(date);

and its work fine, but when I try use datetime with "yyyyMMddHHmmss" I see very bad result, like 17.08.33409 12:34:20 (only month is correct).


Answer:

VFP has both Date and DateTime field types.

The VFP syntax for inserting a date is:

Insert into mytable (mydatefield) values ({^YYYY-MM-DD})

or

Insert into mytable (mydatefield) values (Date(YYYY,MM,DD))

And for a datetime (assuming the field in VFP is a datetime)

Insert into mytable (mydatefield) values ({^YYYY-MM-DD HH:MM:SS})

or

Insert into mytable (mydatefield) values (DateTime(YYYY,MM,DD,HH,MM,SS)) 

So assuming you can extract a text representation of the year, month and day from your Java date you can build up your VFP query from that.

Question:

I know that for a date of this format "23-07-2014", I can use the formatter as "dd-MM-yyyy".

What can I use as a formatter for this date "2014-07-05T00:00:00.000-07:00"?

I am using DateTimeFormatter and want to specify the pattern to parse the above date.

Thanks!


Answer:

Well, can you read it, as human being? Can you identify which part matches what? If so, it's trivial to look at the documentation and work it out for yourself.

For example, the beginning looks like year, month, day (it could be year, day, month, I suppose, but let's assume it's sane). The documentation states that year is mapped by y, and you want 4 numbers, so your format starts with yyyy. By the same token, month of the year is M and day of month is d, so your format starts with yyyy-MM-dd.

T is just a separator between date and time. You then have something that looks like hour, minutes, seconds - looking at the documentation, that's HH:mm:ss.

The following 3 numbers look like milliseconds: `S'.

Finally, a time zone as an offset: Z.

Putting it together:

yyyy-MM-dd'T'HH:mm:ss:.SSSZ

Thats off the cuff, I've not tried it nor double checked it, but it should work. Or at the very least, it should show you how to go about it, by simply reading the documentation.

Question:


Answer:

cannot find class "forPattern()" is one thing, and tells me that there is no such method() is a totally different thing.

What is actually happening is that new Class.Function() is a syntax error.

So, java got confused, it thinks you must be trying to invoke a constructor, so it is telling you that it cannot find the class that contains such a constructor.

Solution: drop the new.

Question:

I have in the form of String the following: month which is in the form of 01-12 day is is in the form of 01-31 year which is in the form e.g. 2019 time which I don't know the form if it can contain milliseconds or is just something like HH:MM All this are supposed to represent a "timestamp" that is exact i.e. not relative to a timezone but e.g. if I did as a simplified example: day/month/year time it should be considered correct regardless of any timezone issues (I hope I explain this clearly). My question is: what is the best way to create some LocalTime or similar object from these so that it won't change due to some locale etc setting and I can do any string manipulation I need correctly or get an epoch?


Answer:

It seems to me that you are asking the impossible or the senseless here.

Let’s take the example from the comments. A passenger books a flight with a time of arrival in İstanbul of 25/04/2019 13:10. By convention arrival time is given in the local time of the arrival airport. Since İstanbul is at UTC offset +03:00, the arrival time is equal to 2019-04-25 10:10 UTC.

Commonly acknowledged good practice is to store dates and times in UTC in your database. If you are using an SQL database, you should normally use its timestamp with time zone datatype (the "with time zone" part is a bit of a lie since you cannot store the timestamp with a time zone of your choice; it is always UTC, but I just said that this is good practice, so this is great).

Say that you’ve got this as input from a user: 25/04/2019 13:10. Converting it to a LocalDateTime is easy (when you know how; code example below). Storing it in UTC is impossible if we don’t know either a time zone (such as Europe/Istanbul or Asia/Istanbul) or a UTC offset (such as +03:00). Imagine that passenger John Doe Jr. has never flown before and doesn’t know of the convention to give arrival time in the local time of the arrival airport. So to him 13:10 could be 13:10 in his own time zone (America/Chicago, equal to 18:10 UTC), 13:10 in the departure time zone (America/New_York, equal to 17:10 UTC), 13:10 UTC, 13:10 in the arrival time zone (equal to 10:10 UTC) or something else.

Now let’s says that we do know that the input is in Europe/Istanbul time zone. Then conversion to UTC is straightforward. We store the time as 2019-04-25 10:10 UTC. Now it won't change due to any time zone setting of the computer or JVM. It’s straightforward to compare with the other UTC times in your database, and you can safely ignore time zones while doing that. When you need to present the time to a user (for instance, print it on a ticket), you convert to Istanbul time (13:10) (or to which time zone the user wants).

Don’t bother with epoch times unless you are using an API that requires them. The standard Java epoch is defined as January 1, 1970 at 00:00 UTC. Note that it is defined in UTC, so it is a well-defined point in time. An epoch time is a signed count of seconds or milliseconds since the epoch. Our example arrival time is 1 556 187 000 seconds since the epoch, so this is your epoch time. As you can see, it’s not meant for human readability. You won’t want to decipher a log file or run a debugging session where time is represented in this way. You don’t want to make any query to a database where time is represented in this way either.

Stay away from string manipulations. Do your date and time work in date and time objects only. When you receive a string, parse it into an appropriate date-time object. Only when you need to present it to a user or transmit it as a string to another system, format it into a string for that purpose.

Java date/time types

Java offers the following date and time types for us:

  • A LocalDateTime is a date and a time of day without UTC offset or time zone, for example 2019-04-25T13:10. So it does not define a point in time.
  • An Instant on the other hand is a point in time without UTC offset or time zone. So it does not define a date and time of day. It prints in UTC (e.g., 2019-04-25T10:10Z) and is internally represented as counts of seconds and nanoseconds since the epoch.
  • An OffsetDateTime is date and time of day with UTC offset, for example 2018-04-25T13:10+03:00. So this does define a point in time and does define date and time of day.
  • A ZonedDateTime is date and time of day with time zone, for example 2018-04-25T13:10+03:00[Europe/Istanbul]. So this too does define a point in time and does define date and time of day.
How it may look in code
    DateTimeFormatter userInputFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu HH:mm");
    String userInput = "25/04/2019 13:10";
    ZoneId arrivalTimeZone = ZoneId.of("Europe/Istanbul");

    // Parse into a LocalDateTime
    LocalDateTime arrivalTimeLocal = LocalDateTime.parse(userInput, userInputFormatter);
    System.out.println("Arrival time:                           " + arrivalTimeLocal);

Arrival time: 2019-04-25T13:10

    // Convert to Instant in order to have a well-defined point in time
    Instant arrivalTime = arrivalTimeLocal.atZone(arrivalTimeZone).toInstant();
    System.out.println("Arrival point in time (printed in UTC): " + arrivalTime);

Arrival point in time (printed in UTC): 2019-04-25T10:10:00Z

    // Convert to UTC for storing in SQL database
    OffsetDateTime arrivalTimeUtc = arrivalTime.atOffset(ZoneOffset.UTC);
    System.out.println("Arrival time in UTC:                    " + arrivalTimeUtc);

Arrival time in UTC: 2019-04-25T10:10Z

Edit: As I said, in your SQL database you would normally want to save your date and time in UTC in a column of datatype timestamp with time zone. The details depend on your database and JDBC driver. I believe that in MySQL (and possibly other DBMSs) the type would be just timestamp. This is a typical example:

    // Save into a database column of datatype timestamp with time zone
    PreparedStatement insert = yourDatabaseConnection.prepareStatement(
            "insert into your_table (your_timestamp_with_time_zone_column) values (?);");
    insert.setObject(1, arrivalTimeUtc);
    int rowsInserted = insert.executeUpdate();

If SQLite hasn’t got a timezone or datetime datatype, prefer to store ISO 8601 format in a character column since this is more readable than epoch time in a numeric column. Instant.toString() produces the string you need for that:

    PreparedStatement insert = yourDatabaseConnection.prepareStatement(
            "insert into your_table (your_varchar_column) values (?);");
    insert.setString(1, arrivalTime.toString());
    int rowsInserted = insert.executeUpdate();

Instant.parse will parse the same string back after retrieval.

    // Convert to arrival time zone, e.g., for printing on ticket
    String arrivalTimeForUser = arrivalTime.atZone(arrivalTimeZone)
            .format(userInputFormatter);
    System.out.println("Formatted arrival time in local time:   " + arrivalTimeForUser);

Formatted arrival time in local time: 25/04/2019 13:10

Links

Question:

import java.text.SimpleDateFormat;
import java.util.Locale;

import org.joda.time.DateTime;
import org.joda.time.Interval;

public class JordaTimeTest {

    public static void main(String[] args) {
        SimpleDateFormat dateFormat1 = new SimpleDateFormat("EEE dd/MM HH:mm", Locale.getDefault());
        SimpleDateFormat dateFormat = dateFormat1;

        Interval interval = new Interval(1499628963860L, 1511809983860L);
        DateTime start = new DateTime(interval.getStart());
        DateTime end = new DateTime(interval.getEnd());

        System.out.println(start.toString(dateFormat.toLocalizedPattern()));
    }
}

I followed the way specified in How to set eclipse console locale/language

I used -Duser.language=da -Duser.country=DK as VM arguments. I'm getting exception:

java.lang.IllegalArgumentException: Illegal pattern component: tt

Any idea to fix this?


Answer:

When setting the locale to da_DK, the method toLocalizedPattern returns EEE tt/MM HH:mm, and tt is not a recognized pattern in Joda-Time.

If you want the output in a specific language, you don't need to change the JVM default locale (because this can affect all other applications running in the same JVM). Instead, you can create a org.joda.time.format.DateTimeFormatter and set the locale only in the formatter:

DateTimeFormatter fmt = DateTimeFormat
    // set pattern
    .forPattern("EEE dd/MM HH:mm")
    // set locale
    .withLocale(new Locale("da", "DK"));
System.out.println(fmt.print(start));
System.out.println(fmt.print(end));

This will output:

sø 09/07 16:36 ma 27/11 17:13

Please note that the output depends on the JVM default timezone: 1499628963860 corresponds to UTC 2017-07-09T19:36:03.860Z, which is 16:36 in my JVM's default timezone (America/Sao_Paulo). In your machine, the values will be different.

If you want to specify a timezone, you could create your dates like:

// create date in UTC
DateTime start = new DateTime(interval.getStart(), DateTimeZone.UTC);

Now the DateTime is in UTC, so the output will be sø 09/07 19:36.

You can also set to a specific timezone using DateTimeZone.forID("zonename"), where zonename is a valid IANA timezone name (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin). Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.

You can get a list of available timezones (and choose the one that fits best your system) by calling DateTimeZone.getAvailableIDs().


As explained in @JB Nizet's comment, there's no need to use SimpleDateFormat (as this is designed to work with java.util.Date and java.util.Calendar).


Java new Date/Time API

Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely "finished" project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".

If you can't (or don't want to) migrate from Joda-Time to the new API, you can ignore this section.

If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.

If you're using Java 6 or 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).

The code below works for both. The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.

You don't need to create an interval and get the start and end from it. You can create the dates directly:

// use system default timezone
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime start = Instant.ofEpochMilli(1499628963860L).atZone(zone);
ZonedDateTime end = Instant.ofEpochMilli(1511809983860L).atZone(zone);

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE dd/MM HH:mm", new Locale("da", "DK"));
System.out.println(start.format(fmt));
System.out.println(end.format(fmt));

The output is:

sø 09/07 16:36 ma 27/11 17:13

If you want to convert to another timezone (instead of JVM default), you can use ZoneId.of("zonename"), or ZoneOffset.UTC to use UTC.

Question:

My date-time format string is : yyyy-MM-dd'T'HH:mm:ss.SSSZ I am using DateTimeFormatter from Joda Time to print my date in the above mentioned format.

Now, consider the date as

2016/04/01 23:00:00

then it should have printed

2016-04-01T23:00:00.000Z

But, it prints

2016-04-01T23:00:00.000+0200

Please help me in getting the date printed in the same format as specified in the string format.


Answer:

According https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html Z has special meaning:

Z       zone-offset

If you want to escape Z quote Z with ':

yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

For example:

java.time.LocalDateTime date = java.time.LocalDateTime.now();
java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter
                .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
java.lang.String text = date.format(formatter);
System.out.println(text);

prints

2016-06-11T18:39:41.962Z

Question:

It's documented here that using the string "MMM" for the month, a text is used and not a number:

Month: 3 or over, use text, otherwise use number.

I'm doing DateTimeFormat.forPattern( "dd/MMM/yyyy" ).print( DateTime.now() ) and instead of returning 05/Apr/2016, it's returning 05/4/2016.

How can I make it return the month in a text format?

Java 6


Answer:

This solves the problem:

DateTimeFormat.forPattern( "dd/MMM/yyyy" ).withLocale( Locale.US ).print( DateTime.now() )

Now I'm getting 05/Apr/2016

Question:

Hi I have Date time format with century I was trying to convert it into string using Joda date time format but I am getting junk data while converting it I am not sure why this is happening

Code

LocalDate date = LocalDate.now();
DateTimeFormatter fmt = DateTimeFormat.forPattern("CCYYMMDDHHMMSSsss");
String str = date.toString(fmt);
System.out.println(str);

this is the output

20170103��0100���

but output should come like this

20160620091223711 

Answer:

If you want the current date and time to be formatted, you should try this:

DateTime dt = DateTime.now();
DateTimeFormatter fmt = DateTimeFormat.forPattern("CCYYMMddHHmmssSSS");
String str = fmt.print(dt);
System.out.println(str);

Here, a DateTime object is used, the pattern is according to specification and the print method of DateTimeFormatter is used.