Why is the JodaTime timezone changing the date?

When the string "2017-04-21T17: 46: 00Z" is passed to the first method, the resulting formatted date string is "06:46 Apr 21, 2017". Why does the hour move eleven o'clock? The input strings are provided by the HTTP server application in JSON. I thought the Z suffix refers to Zulu, i.e. GMT.

private static final String DATE_TIME_FORMAT = "hh:mm dd MMM yyyy";

public static String formatTimestamp(String dateTimestamp) {
    DateTime dateTime = getDateTimeFromTimestamp(dateTimestamp);
    DateTimeFormatter fmt = DateTimeFormat.forPattern(DATE_TIME_FORMAT);
    return fmt.print(dateTime);
}

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    return new DateTime(dateTimestamp);
}

      

I suspect this refers to time zones, but it is not clear how or where. The code works on an Android device in the UK, in GMT time zone.

+3


source to share


2 answers


I have done a test with java 7 and joda-time 2.7 (but not with android version)

How could I reproduce the problem:

// changing my default timezone (because I'm not in UK)
DateTimeZone.setDefault(DateTimeZone.forID("Europe/London"));
// calling your method
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));

      

Output signal

06:46 21 Abr 2017

To check what happened, I changed the date format to:

DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz";

      

Where a

"AM or PM" means, Z

is the offset / id of the time zone, Z

is the β€œshort” name of the time zone, and zzzz

is the β€œlong” name of the time zone. Using this format, the output is:

18:46 PM 21 Apr 2017 +0100 BST British Summer Time

So the generated datetime is 6PM, just one hour ahead, not eleven hours as you thought (in fact, if you change the format to HH

instead HH

, the clock will be 18

instead 06

).

Also note the time zone field: +0100 BST British Summer Time

. The first part ( +0100

) means that this DateTime

one is one hour earlier than GMT, and BST British Summer Time

means it in British Summer Time .




So to make your result equal to your input, you have 2 options:

1. Change the default timezone to UTC:

DateTimeZone.setDefault(DateTimeZone.UTC);
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));

      

The output will be:

05:46 April 21, 2017

If you want to change the hours to 17:46

, change the date format by replacing HH

withHH

2. Use a constructor DateTime

that receives DateTimeZone

:

private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
    // creates a DateTime in UTC
    return new DateTime(dateTimestamp, DateTimeZone.UTC);
}

      

The output will be the same as with alternative 1, but in this case you don't need to change the default timezone.

Alternative 2 makes more sense to me because:

  • you don't need to change the default timezone (which can cause confusion in other parts of the application)
  • You already know that all dates processed by this code are in UTC ( because of the "Z" at the end )
+3


source


Using java.time

Hugo's answer seems to be correct and informative. But FYI, the Joda-Time project is now in maintenance mode , with the team advising moving to the java.time classes . For Android, see the last shot at the bottom at the bottom.

Your input string is in standard ISO 8601 format . The java.time classes use standard formats for parsing and generating strings. Therefore, there is no need to specify a formatting template.

Instant

class represents a moment on the timeline in UTC with nanosecond resolution (up to nine (9) decimal digits).

String input = "2017-04-21T17:46:00Z" ;
Instant instant = Instant.parse( input ) ;

      

instant.toString (): 2017-04-21T17: 46: 00Z

For more flexible formatting, for example, you want to convert an object OffsetDateTime

, you can specify any offset-from-UTC in hours and minutes. We need UTC (zero offset), so we can use a constant ZoneOffset.UTC

.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

      

odt.toString (): 2017-04-21T17: 46Z

Define a formatting template according to your desired format. Note that you must specify Locale

to define (a) the human language for translating the day name, month name, etc., and (b) cultural norms governing abbreviations, capitalization, punctuation, separators, etc.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm dd MMM yyyy" , Locale.US ) ;
String output = odt.format( f ) ;

      

output: 05:46 21 Apr 2017



If you want to see the same moment through the lens of wall clock areas such as Europe/London

or Pacific/Auckland

, apply the time zone to get ZonedDateTime

.

Specify the name of the time zone in the format continent/region

, for example America/Montreal

, Africa/Casablanca

or Pacific/Auckland

. Never use the 3-4 letter abbreviation like EST

or IST

or BST

as they are not real time zones and not standardized or even unique (!).

ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

      

Note that the time of day is the hourly output due to Daylight Saving Time (DST).

zdt.toString (): 2017-04-21T18: 46 + 01: 00 [Europe / London]

See Run Code at IdeOne.com .

About java.time

The java.time framework is built into Java 8 and later. These classes supersede the nasty old legacy datetime classes such as java.util.Date

, Calendar

and . SimpleDateFormat

The Joda-Time project , now in maintenance mode , advise moving to the java.time classes .

To learn more, see the Oracle Tutorial . And search Stack Overflow for many examples and explanations. Specification JSR 310 .

Where can I get the java.time classes?

+1


source







All Articles