Java and Joda-Time: date wrong value - java

I'm getting a wrong date in Joda-Time when I try to parse a string date like this:
2013-11-20 18:20:00 +01:00
I'm expecting to obtain the following date:
Wed Nov 20 19:20:00 CET 2013
but I'm getting:
Wed Nov 20 18:20:00 CET 2013
I'm using Joda-Time and this is my code:
String dateString = "2013-11-20 18:20:00 +01:00";
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z");
DateTime temp = formatter.parseDateTime(dateString);
Date date = temp.toDate();

Expectations
Your expectation is wrong.
The "+01:00" means that time is one hour ahead of UTC/GMT. So, adjusting to UTC means subtracting an hour (17:20) rather than adding (19:20).
The "+01:00" has the same effect as saying CET (Central European Time), meaning one hour ahead of UTC/GMT. So…
2013-11-20 18:20:00 +01:00 = Wed Nov 20 18:20:00 CET 2013
…those are two different ways of stating the same time, same hour.
When I run your code here in United States west coast time, I get… (note the same hours)
temp: 2013-11-20T09:20:00.000-08:00
date: Wed Nov 20 09:20:00 PST 2013
j.u.Date Confusion
As the answer by Stroboskop said, you may be fooled by java.util.Date. The object itself does not have time zone information. Yet it's implementation of the toString() method uses the default time zone in rendering the text to be displayed. Confusing. One of many reasons to avoid using the java.util.Date/Calendar classes. In contrast, Joda-Time DateTime objects do indeed know their own time zone.
Specify Time Zone
Your real problem is an all too common one: Ignoring time zones. By not specifying a time zone, your default time zone was used. As you can see above, my default time zone is different than yours, so I got different results while running the same code.
A better practice is to always specify your time zone. If you want UTC/GMT, say so. If you want CET, say so. (Actually, don't use the three-letter code like CET as they are not standardized and have duplicates – use a time zone name such as Europe/Prague or Europe/Paris.) When parsing that string, specify the time zone to be incorporated within the new DateTime object.
Example Code
Here is some example code showing how to specify the time zone while parsing. Note the call to withZone().
Note that the result of all three parsings is the same moment in the time line of the Universe. To make that point, my code dumps to the console the milliseconds since the Unix Epoch backing each DateTime object. Usually I try to not use nor think about the milliseconds-since-epoch. But here the use of milliseconds-since-epoch proves a point.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
String dateString = "2013-11-20 18:20:00 +01:00";
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z");
// Time Zone list… http://joda-time.sourceforge.net/timezones.html (not quite up-to-date, read page for details)
DateTime dateTimeInUtc = formatter.withZone( DateTimeZone.UTC ).parseDateTime( dateString );
DateTime dateTimeInPrague = formatter.withZone( DateTimeZone.forID( "Europe/Prague" ) ).parseDateTime(dateString);
DateTime dateTimeInVancouver = formatter.withZone( DateTimeZone.forID( "America/Vancouver" ) ).parseDateTime(dateString);
Dump to console…
System.out.println( "dateTimeInUtc: " + dateTimeInUtc + " … In Milliseconds since Unix Epoch: " + dateTimeInUtc.getMillis() );
System.out.println( "dateTimeInPrague: " + dateTimeInPrague + " … In Milliseconds since Unix Epoch: " + dateTimeInPrague.getMillis() );
System.out.println( "dateTimeInVancouver: " + dateTimeInVancouver + " … In Milliseconds since Unix Epoch: " + dateTimeInVancouver.getMillis() );
When run… (Note that whether this code runs on your computer or mine, we both get the same results!)
dateTimeInUtc: 2013-11-20T17:20:00.000Z … In Milliseconds since Unix Epoch: 1384968000000
dateTimeInPrague: 2013-11-20T18:20:00.000+01:00 … In Milliseconds since Unix Epoch: 1384968000000
dateTimeInVancouver: 2013-11-20T09:20:00.000-08:00 … In Milliseconds since Unix Epoch: 1384968000000

Standard question: what time zone are you in? CET?
I assume the parsed DateTime is correct? What timezone does it have?
Bear in mind that Date doesn't have timezones. I'm not even sure if it actually considers Timezone.getDefault().
So, in short it looks like you have a timezone different from +1 and that's why your time is moved by one hour.
-- edit --
hold on. why do you even expect 19:20? The text says 18:20 +1, Joda parses this just like that and Date drops the timezone. That's it.

Related

DateTime to date conversion, not the correct value

I try to convert a string into a datetime:
String dateString = "2015-01-14T00:00:00-04:00";
DateTimeFormatter df = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ");
DateTime dt = df.parseDateTime(dateString);
If I display dt.toDate()
I get: Tue Jan 13 23:00:00 EST 2015
So there is a time problem.
Without the DateTimeFormatter, I get the same issue.
It's getting the correct value - basically 4am UTC, which is midnight in a UTC offset of -04:00 (as per the original text), or 11pm on the previous day for EST (as per the displayed result).
The problem is that you're using java.util.Date.toString(), which always returns the date in the system time zone. Note that a java.util.Date only represents an instant in time - it has no notion of a time zone itself, so its toString() method just uses the system default.
If you want to retain the time zone information (or in this case, the offset from UTC information - you don't have a full time zone) then stick to DateTime instead of converting to Date. Ideally, avoid java.util.Date/java.util.Calendar entirely. Stick to Joda Time and/or java.time.*.

How do I set a Calendar with TimeZone?

I have a timestamp that I am trying to put into a Date object, however when I use Calendar, I am running into a strange problem. I seem to be able to unable to create a Date object with the values I want:
public static void main(String args[]){
Date today = new Date();
int hour = 4, min=0, sec=0, ms=64;
Calendar cal = GregorianCalendar.getInstance();
cal.clear();
cal.setTimeZone(TimeZone.getTimeZone("EDT"));
cal.setTime(today);
cal.set(Calendar.HOUR_OF_DAY,hour);
cal.set(Calendar.MINUTE,min);
cal.set(Calendar.SECOND,sec);
cal.set(Calendar.MILLISECOND,ms);
System.out.println("Time is: "+cal.getTime());
}
This produces:
Time is: Mon Jan 13 23:00:00 EST 2014
which is not the result I am looking for.
However, if I comment out the 'setTimeZone' method call, I get the following result:
Time is: Tue Jan 14 04:00:00 EST 2014
This is the result that I am looking for but I am concerned that if I am running on a machine that is not running in the same time zone, I will not get consistent behavior.
This is the result that I am looking for but I am concerned that if I am running on a machine that is not running in the same time zone
it is the problem. The internal representation should be ok, but it prints on local timezone: representation differs from real content.
use SimpleDateFormat http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html and set TimeZone to see the date on the Zone desired.
The problem here is that Java does not know of the timezone "EDT" (Eastern Daylight Time). As a result, Calendar seems to be setting the timezone to GMT.
The timezone needed here is "America/New_York" or "EST5EDT". When either of these values are used, the correct result is produced.
The list of valid Time Zones can be obtained by calling TimeZone.getAvailableIDs()
It is unfortunate that no warnings are produced when the requested Time Zone is not found.
If you can do away with java.util.Date, you can use joda time API to conveniently set these values as desired:
For your query, you can set your already created Calendar instance as a constructor parameter to DateTime.
DateTime dt = new DateTime(cal);
System.out.println(dt.toDateTimeISO());
Output:
2014-01-14T04:00:00.064-05:00
Calendar.getTime() returns a java.util.Date object. Date objects do not know anything about timezones. The Date object that Calendar.getTime() returns does not know to what timezone the Calendar that it came from is set.
When you print a Date object (for example, by implicitly calling toString() object, as you are doing) it is formatted in the default time zone of the machine you are running it on.
If you want to print a Date in a specific timezone, use a SimpleDateFormat, and set the desired timezone on the SimpleDateFormat object. For example:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("EDT"));
// Will display the date that the calendar is set to in the EDT timezone
System.out.println(df.format(cal.getTime()));
Java Date objects represent the number of milliseconds seconds since January 1, 1970, 00:00:00 GMT due to the fact that the other methods are deprecated. The two ways to "view" a Date object directly are "getTime()" and "toString()" (using "dow mon dd hh:mm:ss zzz yyyy"). Therefore, you are formatting the GMT value to your local timezone.
When working with dates, it is best to think of them as GMT values, and then as a "formatting" exercise when viewing the date.
For comparison, here is that same kind of code but using Joda-Time 2.3.
Avoid the java.util.Date & .Calendar classes.
Never use three-letter codes for time zones. They are neither standardized nor unique. Instead use proper time zone names. In this case, use "America/New_York" or "America/Montreal".
// Use time zone names, such as from this slightly outdated list: http://joda-time.sourceforge.net/timezones.html
DateTimeZone timeZone = DateTimeZone.forID( "America/New_York" );
// Input.
int hour = 4, min = 0, sec = 0, ms = 64;
// Start with now, then adjust the time of day.
DateTime now = new DateTime( timeZone );
DateTime dateTime = now.withHourOfDay( hour ).withMinuteOfHour( min ).withSecondOfMinute( sec ).withMillisOfSecond( ms );
// If needed, translate to a java.util.Date for use with other classes.
java.util.Date date = dateTime.toDate();
Dump to console…
System.out.println( "now: " + now );
System.out.println( "dateTime: " + dateTime );
System.out.println( "date: " + date );
When run…
now: 2014-01-20T21:04:51.237-05:00
dateTime: 2014-01-20T04:00:00.064-05:00
date: Mon Jan 20 01:00:00 PST 2014

Java Current Date/Time displays 1 hour ahead that original time

When I try to print the current date and time using Calender instance, the result I get is 1 hour ahead from the actual time.
I am working in remote machine which runs with EST time zone. Below is what I tried, but nothing works.
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
System.out.println("Current Date & Time: " +calendar.getTime());
o/p:
Time: Sat Dec 28 11:55:10 UTC 2013
But expected o/p:
Time: Sat Dec 28 10:55:10 UTC 2013
All the 3 types give same result. I couldn't understand what I miss out to get the exact date & time. Is this problem related to daylight time saving ?
Could someone help me to overcome this problem. Thanks in Advance.
It is again this old pitfall with java.util.Date: Its toString()-method which you indirectly use when printing calendar.getTime() uses your default time zone, not the time zone of your calendar instance (which you set to 'EST').
Solution:
Date currentTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("Current Date & Time: " + sdf.format(currentTime));
Explanations:
a) In first line no calendar instance is necessary because you are just interested in current global time (the same physical time independent from timezone). Calendar.getInstance() is also more consuming resources. Finally, both expressions new Date() and Calendar.getInstance(...).getTime() have no time zone reference when it is about the internal state. Only the toString()-method of j.u.Date uses default time zone.
b) You need to define an output format which is given in line 2. It is up to you to change it. Just study the pattern documentation of java.text.SimpleDateFormat.
c) You also need to define the time zone in your output format to help the format object to translate the global Date-instance into a timezone-aware representation. By the way, I had choosen the identifier 'America/New_York', not 'EST' because latter form can be sometimes ambigous. You should either choose the first form (IANA- or Olson time zone identifier) or the form 'GMT+/-HH:mm'.
d) The output itself is done with sdf.format(currentTime), not just currentTime (no implicit call of toString()).
e) To answer your question 'Is this problem related to daylight time saving ?': No, the time in time zone EST (America/New_York) is never in DST in december.
Conclusion:
If you can, you should try to avoid j.u.Date and j.u.Calendar because there are too many pitfalls. At the moment JodaTime is a better alternative, although not without issues.
Avoid 3-Letter Time Zone
Never use the 3-letter time zone codes. They are neither standardized nor unique. Your "EST" can mean at least these:
Eastern Standard Time (USA)
Eastern Standard Time (Australia)
Eastern Brazil Standard Time
Use time zone names.
Avoid j.u.Date/Calendar
You have discovered one of the many reasons to avoid using java.util.Date & java.util.Calendar classes bundled with Java: A Date instance has no time zone information yet its toString method confusingly renders a string based on your Java environment's default time zone.
Use Joda-Time
Use a competent date-time library. In Java that means either Joda-Time, or in Java 8, the new java.time.* classes (inspired by Joda-Time).
Example code…
// Default time zone
DateTime dateTime_MyDefaultTimeZone = new DateTime();
// Specific time zone. If by "EST" you meant east coast of United States, use a name such as New York.
DateTimeZone timeZone = DateTimeZone.forID( "America/New_York" );
DateTime dateTime_EastCoastUS = new DateTime( timeZone );
Dump to console…
System.out.println( "dateTime_MyDefaultTimeZone: " + dateTime_MyDefaultTimeZone );
System.out.println( "dateTime_EastCoastUS: " + dateTime_EastCoastUS );
System.out.println( "date-time in UTC: " + dateTime_EastCoastUS.toDateTime( DateTimeZone.UTC ) );
When run…
dateTime_MyDefaultTimeZone: 2013-12-28T18:51:18.485-08:00
dateTime_EastCoastUS: 2013-12-28T21:51:18.522-05:00
date-time in UTC: 2013-12-29T02:51:18.522Z

Explaination of time format (Google Directions API)

I have read the documentation of the Google Directions API for making a direction request. An example of a URL is given as
http://maps.googleapis.com/maps/api/directions/json?origin=Brooklyn&destination=Queens&sensor=false&departure_time=1343605500&mode=transit
The value of the departure_time variable is supposed to reflect the following information:
July 30, 2012 at 09:45 am.
Can someone please explain this time format.
Thanks.
It's a timestamp - seconds elapsed since the Unix epoch, 1970-01-01 00:00:00 UTC. If you want "right now" in that format, you can use System.currentTimeMillis() / 1000, or if you have a Date object, you can use date.getTime() / 1000.
That's an epoch unix timestamp (number of seconds since Jan 1 1970). You can create a date by
Date d = new Date(1343605500L);
Or use http://www.epochconverter.com/
Flaw In Google Documentation
Googling for that particular number led to places such as this similar StackOverflow.com question. These pages lead me to conclude that the documentation for Google Directions API is flawed.
You and others report that the doc says 1343605500 = July 30, 2012 at 09:45 am in New York. But that is incorrect. Both the day of month and the hour of day are wrong.
1343605500 seconds from the beginning of the year 1970 UTC/GMT:
In New York is 2012-07-29T19:45:00.000-04:00
In UTC/GMT is 2012-07-29T23:45:00.000Z
Getting Date-Time From A Number
As the other answers stated, apparently Google is handing you the number of seconds since the Unix Epoch at the beginning of the year 1970 in UTC/GMT (no time zone offset).
Alternatively to using java.util.Date/Calendar classes, you can use the third-party open-source Joda-Time library.
Here is some example source code to show you how to parse the text into a date-time with time zone.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
// Starting data.
String string = "1343605500";
String timeZoneName = "America/New_York";
// Convert string of seconds to number of milliseconds.
long millis = Long.parseLong( string ) * 1000 ; //
// Specify time zone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( timeZoneName );
// Instantiate DateTime object.
DateTime dateTime = new DateTime( millis, timeZone );
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTime in UTC/GMT: " + dateTime.toDateTime( DateTimeZone.UTC ) );
When run…
dateTime: 2012-07-29T19:45:00.000-04:00
dateTime in UTC/GMT: 2012-07-29T23:45:00.000Z
When using a count from epoch, you must be careful about:
Which epoch (Unix Time is but one of several possibilities)
Precision of count (seconds, milliseconds, nanoseconds)

Epoch is not epoch if do a new Date(0L). Why?

My problem is pretty straigtforward explained :
if I do this :
public class Main {
public static void main(String[] args) throws Exception {
Date d = new Date(0L );
System.out.println(d);
}
}
I get the following output : Thu Jan 01 01:00:00 CET 1970
According to the doc, I was expecting : Thu Jan 01 00:00:00 CET 1970
I would like was going wrong...
EDIT :
Indeed, I read the doc too fast. I should have Thu Jan 01 00:00:00 GMT 1970
So, how can I force the use of GMT, and ignore all local time ?
Edit, Solution :
public static void main(String[] args) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("H:m:s:S");
SimpleTimeZone tz = new SimpleTimeZone(0,"ID");
sdf.setTimeZone(tz) ;
Date d = new Date(0L );
System.out.println( sdf.format(d));
}
The Epoch is defined as 00:00:00 on 1970-1-1 UTC. Since CET is UTC+1, it's equal to 1AM your time.
If you look at the Date(long) constructor, you'll see that it expects the value to be the number of milliseconds since the epoch, UTC:
Allocates a Date object and
initializes it to represent the
specified number of milliseconds since
the standard base time known as "the
epoch", namely January 1, 1970,
00:00:00 GMT.
Regarding your desire to force GMT instead of your local time zone: In short, the Date instance always uses GMT. If you just want to format the output String so that it uses GMT have a the DateFormat class, and specifically, its setTimeZone() method.
This might be related to your locale settings. Assuming you're French and not French-Canadian, it would seem as if your timestamp is being treated as timestamp without timezone, and the Date constructor attempts to correct for this, adding an hour to the date.
If this is undocumented behavior or not, I cannot tell you.
Edit: Read error: CET != UTC :/
So yeah, Locale time zone.
Reedit: For utter and absolute clarity.
Output: Thu Jan 01 01:00:00 CET 1970
Your expected output: Thu Jan 01 00:00:00 CET 1970
Actual expected output: Thu Jan 01 00:00:00 GMT 1970 ( ≡ Thu Jan 01 01:00:00 CET 1970)
tl:dr
Instant.EPOCH
.toString()
1970-01-01T00:00:00Z
Date::toString lies
You've learned one of the many reasons to avoid using the java.util.Date/Calendar classes: a Date instance has no time zone information, yet it's toString method uses your default time zone when rendering a string for display. Confusing because it implies the Date has a time zone when in fact it does not.
Avoid Date/Calendar
Instead of Date/Calendar, you should be using Joda-Time or the new Java 8 classes, java.time.* from JSR 310.
java.time
Use the Instant class as the equivalent of Date, a moment on the timeline in UTC.
Instant.now()
For the epoch reference date, use the constant.
Instant.EPOCH.toString()
1970-01-01T00:00:00Z
If by "ignore all time" you mean that you really want a date-only value without time-of-day, use the LocalDate class.
LocalDate.ofEpochDay( 0L )
1970-01-01
Joda-Time Example
Update: The Joda-Time project is now in maintenance mode with the team advising migration to the java.time classes.
In Joda-Time, a DateTime instance does indeed know its own time zone. You can use a formatter to create string outputs in other time zones, if desired.
Here's your code aiming at the Unix time Epoch, but using Joda-Time 2.3.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone timeZone_Paris = DateTimeZone.forID( "Europe/Paris" );
DateTime epochParis = new DateTime( 0L, timeZone_Paris );
DateTime epochUtc = new DateTime( 0L, DateTimeZone.UTC );
Dump to console…
System.out.println( "epochParis: " + epochParis );
System.out.println( "epochUtc: " + epochUtc );
When run…
epochParis: 1970-01-01T01:00:00.000+01:00
epochUtc: 1970-01-01T00:00:00.000Z
Convert To UTC/GMT
So, how can i force the use of GMT, and ignore all local time ?
To use UTC/GMT (no time zone offset), either:
Convert a DateTime to another instance with a different time zone(Joda-Time makes things immutable for thread-safety, so we don't actually convert, we create new instances based on old ones.)
Use a formatter to create strings displayed for a specified time zone.
// To use UTC/GMT instead of local time zone, create new instance of DateTime.
DateTime nowInParis = new DateTime( timeZone_Paris );
DateTime nowInUtcGmt = nowInParis.toDateTime( DateTimeZone.UTC );
Dump to console…
System.out.println( "nowInParis: " + nowInParis );
System.out.println( "nowInUtcGmt: " + nowInUtcGmt );
When run…
nowInParis: 2013-12-22T08:40:01.443+01:00
nowInUtcGmt: 2013-12-22T07:40:01.443Z
CET is one hour ahead of GMT, which is the time zone used to define the Epoch.

Categories

Resources