Odd behavior during timezone conversion - java

I am trying to convert between a date printed out in an EST timezone into a date printed out in GMT/UTC
package com.stefano;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class MainEntry {
/**
* #param args
* #throws ParseException
*/
public static void main(String[] args) throws ParseException {
String dateTime = "1307011200"; //12:00PM 01 July 2013
System.out.println("Input -> " + dateTime);
SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmm");
format.setTimeZone(TimeZone.getTimeZone("EST"));
Date date = format.parse(dateTime);
System.out.println("Intermediate -> " + date);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("Output -> " + format.format(date));
}
}
The output it gives is:
Input -> 1307011200
Intermediate -> Mon Jul 01 17:00:00 BST 2013
Output -> 1307011600
Even though the time difference between EST and GMT is always 5, it is somehow getting involved with BST.
I cannot use Joda-Time.

The javadoc of the SimpleDateFormat.parse(String) method refers to the parse(String, ParsePosition) method, that says:
This parsing operation uses the calendar to produce a Date. As a result, the calendar's date-time fields and the TimeZone value may have been overwritten, depending on subclass implementations. Any TimeZone value that has previously been set by a call to setTimeZone may need to be restored for further operations.
According to this you can't use this method to tell the SimpleDateFormat which timezone
the given date is in.
You can fix this method like this:
String dateTime = "1307011200"; // 12:00PM 01 July 2013
dateTime += " EST"; // append the timezone information to the input string
System.out.println("Input -> " + dateTime);
SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmm z"); // tell the formatter to look for the timezone info
Date date = format.parse(dateTime);
System.out.println("Intermediate -> " + date);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("Output -> " + format.format(date));
This will also print the Date object using your local timezone, but it shows a way to parse the dateTime string using a given timezone.

The answer by zovits is correct.
US East Coast Offset
If by EST you mean the east coast of the United States (and parts of Canada), then your statement the time difference between EST and GMT is always 5 is incorrect. With Daylight Saving Time (DST), the offset may be -05:00 or -04:00. Indeed, your specified date-time does have DST in effect.
Avoid 3-4 Letter Time Zone Codes
Those three or four letter time zone codes are neither standardized nor unique. Avoid them. Use proper time zone names, most of which are continent+city.
Comparison To Joda-Time
For comparison, here is some Joda-Time example code. The java.util.Date & .Calendar classes bundled with Java are so notoriously troublesome that every Java programmer should move to either Joda-Time or the new Java 8 java.time package (inspired by Joda-Time, defined by JSR 310).
While a java.util.Date seems to have a time zone but actually does not, note that a Joda-Time DateTime does truly know its own assigned time zone.
Joda-Time uses the ISO 8601 standard for its defaults. You can use other formats as well, as seen with the Montréal example below.
Example Code
String input = "1307011200"; //12:00PM 01 July 2013
DateTimeFormatter formatterSmooshed = DateTimeFormat.forPattern( "yyMMddHHmm" );
DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime dateTimeNewYork = formatterSmooshed.withZone( timeZoneNewYork ).parseDateTime( input );
DateTime dateTimeUtc = dateTimeNewYork.withZone( DateTimeZone.UTC );
String outputMontréal = DateTimeFormat.forStyle( "FF" ).withLocale( Locale.CANADA_FRENCH ).print( dateTimeNewYork );
String outputSmooshed = formatterSmooshed.print( dateTimeNewYork ); // Expect same as input.
Dump to console…
System.out.println( "input: " + input );
System.out.println( "dateTimeNewYork: " + dateTimeNewYork );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "outputMontréal: " + outputMontréal );
System.out.println( "outputSmooshed: " + outputSmooshed );
When run…
input: 1307011200
dateTimeNewYork: 2013-07-01T12:00:00.000-04:00
dateTimeUtc: 2013-07-01T16:00:00.000Z
outputMontréal: lundi 1 juillet 2013 12 h 00 EDT
outputSmooshed: 1307011200

Related

Convert UK time to South African time in Java

I have a football match date and time as UK time.
I am running this service in South Africa so it must display the fixture date and time as South African time. At the moment I am doing this:
int kickoffHour = fixture.getTime().getHours() + 2;
However - when it reaches end of March 2016 this will have to change again to "+ 1" instead of "+ 2". Now I can't keep changing this so I want something that will automatically pick up that its DST or BST and do the conversion.
I have tried something like this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Date date = sdf.parse(fixture.getDate() + " " + fixture.getTime());
But that gave me like 2am or something. My date in the database is: 2015-12-16 and the time in the database is 16:00:00 - after parsing I get Wed Dec 16 02:00:00 SAST 2015
Apparently you are referring to adjustments needed for Daylight Saving Time (DST). You should leave such work to a good date-time library rather than manage these details yourself.
Unfortunately, the old date-time classes bundled with early versions of Java are not good. While a valiant effort, they have proven to be troublesome and confusing, flawed in both design and implementation. Avoid java.util.Date/.Calendar and java.text.SimpleDateFormat.
java.time
The java.time framework built into Java 8 and later supplants the troublesome old java.util.Date/.Calendar classes. The new classes are inspired by the highly successful Joda-Time framework, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen-Extra project. See the Tutorial.
By the way, best practice is to do all your business logic, data storage & exchange, and database work in UTC. Use zoned date-time values only when expected by the user or data sink. However, it appears you have been given a string in London time, so let's go with that.
String input = "2015-12-16 16:00:00"; // Local date-time in United Kingdom (London).
Use proper time zone names. Never use the 3-4 letter codes commonly seen as they are neither standardized nor unique.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyy-MM-dd HH:mm:ss" );
Your string input lacks embedded info about its offset-from-UTC or time zone. So, we will assume the String represents local time in Europe/London. We communicate this assumption to the DateTimeFormatter, as it would otherwise interpret the incoming String as belonging to the JVM’s current default time zone. Note that java.time uses immutable objects, so rather than alter the formatter we generate a new instance based on values take from the old instance.
ZoneId zoneId_London = ZoneId.of ( "Europe/London" );
formatter = formatter.withZone ( zoneId_London ); // Specify the zone by which to interpret this date-time input string as it lacks any offset or time zone info.
ZonedDateTime zdt_UK = ZonedDateTime.parse ( input , formatter );
With a London date-time in hand, we can adjust into a South Africa time zone.
ZoneId zoneId_Johannesburg = ZoneId.of ( "Africa/Johannesburg" );
ZonedDateTime zdt_ZA = zdt_UK.withZoneSameInstant ( zoneId_Johannesburg );
Dump to console.
System.out.println ( "input: " + input + " in zone: " + zoneId_London + " = " + zdt_UK );
System.out.println ( "zdt_UK: " + zdt_UK + " adjusted to zone: " + zoneId_Johannesburg + " is: " + zdt_ZA );
input: 2015-12-16 16:00:00 in zone: Europe/London = 2015-12-16T16:00Z[Europe/London]
zdt_UK: 2015-12-16T16:00Z[Europe/London] adjusted to zone: Africa/Johannesburg is: 2015-12-16T18:00+02:00[Africa/Johannesburg]
Lastly, we do most of our work in UTC. For that, extract a Instant object which is a moment on the timeline in UTC.
Instant instant = zdt_ZA.toInstant();
if fixture.getDate() + " " + fixture.getTime() works fine, at the end you will get the String as "2015-12-16 16:00:00".
Then I simply format the returning date. Mine works fine..
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Date date = sdf.parse("2015-12-16 16:00:00");
//Date date = sdf.parse("2016-03-31 23:50:50");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("Africa/Johannesburg"));
System.out.println(df.format(date));
}
Output of this code is 2015-12-16 18:00:00
When I use commented date object, result was 2016-04-01 00:50:50
You can simply get the time values from the fixture and use calendar to auto convert your time zone. I am keeping in mind that your system timezone matches the expected output timezone. Please check the below code snipet, w/o using fixture object and using hard coded value.
Calendar cal = Calendar.getInstance();
cal.setTimeZone(java.util.TimeZone.getTimeZone("Europe/London"));
cal.set(Calendar.HOUR, 16);
cal.set(Calendar.MINUTE, 0);
cal.set(2015, 11, 24);
System.out.println(cal.getTimeZone());
System.out.println(cal.getTime()); //printing in IST (my local time)
You should have a Date object from your database.
If you want to print it, use your SimpleDateFormat setting its timezone to South Africa "Africa/Johannesburg" and it will work.
Date myDate;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Africa/Johannesburg"));
System.out.println(sdf.format(myDate));

JodaTime - how to get current time in UTC

I want to get the current time in UTC. What I do so far is following (just for testing purposes):
DateTime dt = new DateTime();
DateTimeZone tz = DateTimeZone.getDefault();
LocalDateTime nowLocal = new LocalDateTime();
DateTime nowUTC = nowLocal.toDateTime(DateTimeZone.UTC);
Date d1 = nowLocal.toDate();
Date d2 = nowUTC.toDate();
L.d("tz: " + tz.toString());
L.d("local: " + d1.toString());
L.d("utc: " + d2.toString());
d1 is my local time, that's fine
d2 is my local time + 1, but should be local time - 1...
My local time zone is UTC+1 (according to the debug output and the list here: https://www.joda.org/joda-time/timezones.html)...
How do I correctly convert from one time zone to another (inclusive the millisecond representation)?
EDIT
I need the date/milliseconds... It's NOT about displaying the time correctly....
EDIT 2
Now, with the help of a comment and an answer, I tried following:
DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowLocal = new DateTime();
LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);
Date dLocal = nowLocal.toDate();
Date dUTC = nowUTC.toDate();
Date dUTC2 = nowUTC2.toDate();
L.d(Temp.class, "------------------------");
L.d(Temp.class, "tz : " + tz.toString());
L.d(Temp.class, "local : " + nowLocal + " | " + dLocal.toString());
L.d(Temp.class, "utc : " + nowUTC + " | " + dUTC.toString()); // <= WORKING SOLUTION
L.d(Temp.class, "utc2 : " + nowUTC2 + " | " + dUTC2.toString());
OUTPUT
tz : Europe/Belgrade
local : 2015-01-02T15:31:38.241+01:00 | Fri Jan 02 15:31:38 MEZ 2015
utc : 2015-01-02T14:31:38.241 | Fri Jan 02 14:31:38 MEZ 2015
utc2 : 2015-01-02T14:31:38.241Z | Fri Jan 02 15:31:38 MEZ 2015
What I wanted was, that the local date displays 15 o'clock and utc date displays 14 o'clock...
For now, this seems to work...
----- EDIT3 - Final solution -----
Hopefully, this is a good solution... I think, i respects all tipps i got...
DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowUTC = new DateTime(DateTimeZone.UTC);
DateTime nowLocal = nowUTC.withZone(tz);
// This will generate DIFFERENT Dates!!! As I want it!
Date dLocal = nowLocal.toLocalDateTime().toDate();
Date dUTC = nowUTC.toLocalDateTime().toDate();
L.d("tz : " + tz.toString());
L.d("local : " + nowLocal + " | " + dLocal.toString());
L.d("utc : " + nowUTC + " | " + dUTC.toString());
Output:
tz : Europe/Belgrade
local : 2015-01-03T21:15:35.170+01:00 | Sat Jan 03 21:15:35 MEZ 2015
utc : 2015-01-03T20:15:35.170Z | Sat Jan 03 20:15:35 MEZ 2015
You're making it far more complicated than you need to:
DateTime dt = new DateTime(DateTimeZone.UTC);
No conversion required at all. If you find you actually need to convert, you can use withZone. I'd suggest you avoid going via LocalDateTime, however, as that way you can lose information due to time zone transitions (two different instants can have the same local time in the same time zone, because clocks go back and repeat local time.
Having said all of this, for the sake of testability I personally like using a Clock interface which allows me to get the current time (e.g. as an Instant). You can then use dependency injection to inject a real system clock when running in production, and a fake clock with a preset time for tests. Java 8's java.time package has this idea built into it, btw.
You can also use the static method now which makes it even more readable
DateTime.now(DateTimeZone.UTC)
Use this
DateTime.now().withZone(DateTimeZone.UTC)
and if you want to format, you can use
DateTime.now().withZone(DateTimeZone.UTC).toString("yyyyMMddHHmmss")
Please try to listen to Jon Skeets good advise and comments. Here an additional explanation. Your edit-2 contains a mistake:
DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowLocal = new DateTime();
LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);
Date dLocal = nowLocal.toDate();
Date dUTC = nowUTC.toDate();
Date dUTC2 = nowUTC2.toDate();
If you call toDate() on an object nowUTC of type LocalDateTime then you can get surprises - see javadoc. Joda-Time claims to use the same fields in java.util.Date as in nowUTC. What does this mean? Let's analyze:
nowUTC.toString() produces 2015-01-02T14:31:38.241 That is without timezone (note the missing Z at the end), so it is just a plain local timestamp. By context, we know it was generated in UTC. In your next step however, you convert it to a java.util.Date using the mentioned method above. This method combines the local timestamp with the system timezone (Belgrade) PRESERVING the FIELDS, hence CHANGING the instant. So you have finally miscorrected your instant. And your second line is wrong.
If you just want
utc date displays 14 o'clock
then don't use the questionable and misleading conversion method Joda-Time offers. Use instead a dedicated formatter with the pattern "EEE MMM dd HH:mm:ss zzz yyyy" or similar (Joda-Time offers DateTimeFormatter). Set the UTC-offset on this formatter and print. Done. Abandon completely any call of java.util.Date.toString(). This way, you don't even need to do any dangerous conversion at all.
From here: http://www.joda.org/joda-time/userguide.html#Changing_TimeZone
// get current moment in default time zone
DateTime dt = new DateTime();
// translate to London local time
DateTime dtLondon = dt.withZone(DateTimeZone.forID("Europe/London"));
The resulting value dtLondon has the same absolute millisecond time, but a different set of field values.
You can substitute `Europe/London' for the timezone you want (UTC). See this list of proper time zone names.
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
// or SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy KK:mm:ss a Z" );
sdf.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
System.out.println( sdf.format( new Date() )
);
Instead of System.out.println( sdf.format( new Date() ) put your local date
I fixed this with this converter
public class DateTimeConverter implements AttributeConverter<DateTime, Date> {
#Override
public Date convertToDatabaseColumn(DateTime attribute) {
return attribute == null ? null
: new Date(attribute
.withZone(DateTimeZone.UTC)
.withZoneRetainFields(DateTimeZone.getDefault())
.getMillis());
}
#Override
public DateTime convertToEntityAttribute(Date dbData) {
return dbData == null ? null
: new DateTime(dbData.getTime())
.withZoneRetainFields(DateTimeZone.UTC)
.withZone(DateTimeZone.getDefault());
}
}
Dates are stored as UTC and recovered with your current time zone

Converting calendar to date in dd-MMM-yyyy format

I am trying to add 17 days to 10-APR-2014 and convert the date to dd-MMM-yyyy format, but I am getting Sun Apr 27 00:00:00 GMT+05:30 2014.
Here is my code:
import java.util.*;
import java.text.*;
public class HelloWorld{
public static void main(String []args){
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
Calendar c = Calendar.getInstance();
c.setTime(new Date());
c.add(Calendar.DATE, 17);
String output = sdf.format(c.getTime());
System.out.println(output);
System.out.print(new SimpleDateFormat("dd-MMM-yyyy").parse(output));
}
}
How can I make the output be 27-Apr-2014?
You are printing a Date parsed from a String formatted from the calendar date.
Instead, print the formatted calendar date:
System.out.print(new SimpleDateFormat("dd-MMM-yyyy").format(c.getTime()));
If displaying and using the dates is disjunct, do this:
Date date; // from Calendar or wherever
String str = new SimpleDateFormat("dd-MMM-yyyy").format(date));
// display str
Then when you want to do something with a selected date:
String selection;
Date date = new SimpleDateFormat("dd-MMM-yyyy").parse(selection));
// do something with date
The answer by Bohemian is correct. Here I present an alternative solution.
Avoid j.u.Date
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use either Joda-Time or the new java.time package in Java 8.
Date-Only
If you need only a date, without any time component, both Joda-Time and java.time offer a LocalDate class.
Time Zone
Even for a date-only, you still need a time zone to get "today". At any moment the date may vary ±1 depending on your location on the globe. If you do not specify a time zone, the JVM's default time zone will be applied.
Example Code
Here is some example code in Joda-Time 2.3.
Determine "today" based on some time zone. Add seventeen days.
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
LocalDate today = new LocalDate( timeZone );
LocalDate seventeenDaysLater = today.plusDays( 17 );
Generate a String representation of the date-time value…
DateTimeFormatter formatter = DateTimeFormat.forPattern( "dd-MMM-yyyy" );
String output = formatter.print( seventeenDaysLater );
Dump to console…
System.out.println( "today: " + today );
System.out.println( "seventeenDaysLater: " + seventeenDaysLater );
System.out.println( "output: " + output );
When run…
today: 2014-04-21
seventeenDaysLater: 2014-05-08
output: 08-May-2014

UTC date parsing inconsistency in Java

Something weird is happening while parsing a UTC/GMT date. I set the date format as
"yyyy-MM-dd'T'HH:mm:ss'Z'"
where Z is for UTC. And I give following date string to parse:
String startTimestampString = "2013-10-02T00:00:00Z";
I hope to get same date as output but instead it shows
2013-10-01 17:00:00.0
Now sure from where this 7 hour lag coming from?
Code:
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class DateTest {
public static void main(String[] args) throws ParseException {
SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
date.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(TimeZone.getTimeZone("UTC").toString());
String startTimestampString = "2013-10-02T00:00:00Z";
long startTimestamp = date.parse(startTimestampString).getTime();
System.out.println(String.format("Long %d and timestamp %s", startTimestamp, new Timestamp(startTimestamp).toString()));
}
}
Output:
sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
Long 1380672000000 and timestamp 2013-10-01 17:00:00.0 // ERROR timestamp should have been 2013-10-02 00:00:00.0
java.util.Date Has No Time Zone
As the comments said, your problem is not understanding the confusing way in which java.util.Date works.
A Date object has no time zone, but seems to have one because its toString method applies your JVM's default time zone when generating the textual representation (the String being returned).
This poor design choice by the Java team has caused so much confusion, including countless similar Questions on StackOverflow.
The Date Is Not The String
A key idea here is that the String generated by the toString method is an entirely new object. This string is not the Date. The string is a particular representation of that moment in history as seen from you default time zone. The same moment in history appears as two different time-of-day values when seen from the Paris or Montréal or Kolkata time zones.
Avoid java.util.Date
Do not waste your time with java.util.Date and .Calendar and SimpleDateFormat. They are notoriously troublesome. Use Joda-Time or new java.time package in Java 8 (inspired by Joda-Time).
Joda-Time
Example code in Joda-Time 2.3. Your format is in the standard ISO 8601 format. Joda-Time uses ISO 8601 as its defaults, so no need for parsers/formatters in your case. Joda–Time automatically uses built-in formatters to parse ISO 8601 compliant strings.
String input = "2013-10-02T00:00:00Z";
DateTimeZone timeZoneParis = DateTimeZone.forID( "Europe/Paris" );
DateTime dateTimeParis = new DateTime( input, timeZoneParis );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );
DateTime dateTimeIndia = dateTimeParis.withZone( DateTimeZone.forID( "Asia/Kolkata" ) );
DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTimeFormatter formatter = DateTimeFormat.forStyle( "FF" ).withLocale( Locale.CANADA_FRENCH );
Dump to console…
System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );
System.out.println( "dateTimeMontréal formatted: " + formatter.print( dateTimeMontréal ) );
System.out.println( "dateTimeIndia: " + dateTimeIndia );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
When run…
dateTimeParis: 2013-10-02T02:00:00.000+02:00
dateTimeMontréal: 2013-10-01T20:00:00.000-04:00
dateTimeMontréal formatted: mardi 1 octobre 2013 20 h 00 EDT
dateTimeIndia: 2013-10-02T05:30:00.000+05:30
dateTimeUtc: 2013-10-02T00:00:00.000Z

Losing an hour when returning a January 1970 Date from milliseconds

I have the following code that takes a String of milliseconds (will be from an RSS feed so will be a String, the example below is a quick test program) and converts those millis into a Date object.
public static void main(String[] args) {
String ms = "1302805253";
SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(Long.parseLong(ms));
try {
String dateFormat = dateFormatter.format(calendar.getTime());
System.out.println("Date Format = " + dateFormat);
Date dateParse = dateFormatter.parse(dateFormatter.format(calendar.getTime()));
System.out.println("Date Parse = " + dateParse);
} catch (ParseException e) {
// TODO: handle exception
}
}
Output:
Date Format = Fri, 16 Jan 1970 02:53:25 GMT
Date Parse = Fri Jan 16 03:53:25 GMT 1970
As you can see, between the formatting of the calendar object and parsing of the resulting String, an hour is being lost. Also, the formatting of the output has changed. Can anyone help me as to why this is happening, and how to get around it? I want the Date object to be the same format as the "Date Format" output.
I believe it's happening because the UK didn't actually use GMT in 1970, and Java has a bug around that... it will format a date in 1970 as if the UK were using GMT, but without actually changing the offset. Simple example:
Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss zzz");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(sdf.format(date));
Result:
01 Jan 1970 01:00:00 GMT
Note that it claims it's 1am GMT... which is incorrect. It was 1am in Europe/London time, but Europe/London wasn't observing GMT.
Joda Time gets this right in that it prints out BST - but Joda Time doesn't like parsing values with time zone abbreviations. However, you can get it to use time zone offets instead:
import org.joda.time.*;
import org.joda.time.format.*;
public class Test {
public static void main(String[] args) throws Exception {
DateTime date = new DateTime(0, DateTimeZone.forID("Europe/London"));
DateTimeFormatter formatter = DateTimeFormat.forPattern(
"dd MMM yyyy HH:mm:ss Z");
String text = formatter.print(date); // 01 Jan 1970 01:00:00 +0100
System.out.println(text);
DateTime parsed = formatter.parseDateTime(text);
System.out.println(parsed.equals(date)); // true
}
}
The Answer by Jon Skeet is correct.
java.time
Let’s run the same input through java.time to see the results.
Specify a proper time zone name. Never use the 3-4 letter abbreviation such as BST, EST, or IST as they are not true time zones, not standardized, and not even unique(!). So we use Europe/London.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
String input = "1302805253";
long millis = Long.parseLong ( input );
Instant instant = Instant.ofEpochMilli ( millis );
Apply a time zone to produce a ZonedDateTime object.
ZoneId zoneId = ZoneId.of ( "Europe/London" );
ZonedDateTime zdt = instant.atZone ( zoneId );
Dump to console. We see indeed that Europe/London time is an hour ahead of UTC at that moment. So the time-of-day is 02 hours rather than 01 hours. Both represent the same simultaneous moment on the timeline, just viewed through the lenses of two different wall-clock times.
System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt );
input: 1302805253 | instant: 1970-01-16T01:53:25.253Z | zdt: 1970-01-16T02:53:25.253+01:00[Europe/London]
Whole seconds
By the way, I suspect your input string represents whole seconds since epoch of 1970 UTC rather than milliseconds. Interpreted that as seconds we get a date in 2011, in the month this Question posted.
String output = Instant.ofEpochSecond ( Long.parseLong ( "1302805253" ) ).atZone ( ZoneId.of ( "Europe/London" ) ).toString ();
2011-04-14T19:20:53+01:00[Europe/London]
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time.

Categories

Resources