I have some code that uses Calendar.set() to return the beginning of the hour for a given date value. I encountered the following issue on Sunday Nov 4th, 2012 (Eastern Timezone - EDT to EST switchover):
public void testStartOfHourDST1() {
Calendar cal = Calendar.getInstance();
long time = 1352005200000L; // Nov 4, 2012, 1AM EDT
cal.setTimeInMillis(time);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
System.out.println(new Date(time));
System.out.println(new Date(cal.getTimeInMillis()));
System.out.println(System.getProperty("java.version"));
assertEquals(cal.getTimeInMillis(), time); // fails
return;
}
Ouput:
Sun Nov 04 01:00:00 EDT 2012
Sun Nov 04 01:00:00 EST 2012
1.6.0_35
Perhaps this is not the correct way to be using calendar, but running the same test for the next hour (or previous hour) works fine. Is this a JVM issue?
Thanks
It's not really an issue, in the sense that it is deterministic and doing what it was programmed to do. It's an issue if you would prefer that it pick the earlier of the two 1ams!
After changing fields on the Calendar the only information it has is "1am in US/Eastern". Well, your timezone had two 1ams that day, which one is it supposed to pick? The authors of OpenJDK made a decision that when presented with this ambiguity, they would always interpret it as the later one, in standard time. This comment is from java.util.GregorianCalendar OpenJDK 6:
// 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
// can be in standard or DST. Both are valid representations (the rep
// jumps from 1:59:59 DST to 1:00:00 Std).
// Again, we assume standard time.
If you print out the actual values of the numbers you will see cal.getTimeInMillis() has actually been changed by an hour from the value of time.
Getting the correct time zone is very important. For example, as I'm sure you are aware the system current time in milliseconds is measured from midnight on the 1st of January 1970. This is well documented. The Date constructor JavaDoc says:
public Date(long date)
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.
which is fine, but makes the output of this program a little hard to understand at first:
import java.util.Date;
import java.util.TimeZone;
import java.text.SimpleDateFormat;
public class Demo {
public static void main(String[] args) {
TimeZone tz = TimeZone.getTimeZone("Europe/London");
Date d = new Date(-3600000);
SimpleDateFormat df = new SimpleDateFormat("MMMM dd, yyyy HH:mm:ss.SSS z");
df.setTimeZone(tz);
System.out.println(String.format("%8dms -> %s",
Long.valueOf(d.getTime()) ,df.format(d)));
d.setTime(0);
System.out.println(String.format("%8dms -> %s",
Long.valueOf(d.getTime()) ,df.format(d)));
}
}
The output is:
-3600000ms -> January 01, 1970 00:00:00.000 GMT
0ms -> January 01, 1970 01:00:00.000 GMT
As you can see, the epoch is apparently displaced by an hour!
Except it is not. If you use the "GMT" time zone explicitly, all is well. The "Europe/London" time zone is simply tricky like that.
When working with Calendars, understand the time zone you are using or be caught out.
Related
I need the current date in following format at 00:00:00 CST time.
Like say current date is July 9 2021 Then I need that date along with 00:00:00 time.
Expected Output:
Fri Jul 09 00:00:00 CST 2021
Current code:
LocalDateTime date= LocalDateTime.now().with(LocalTime.MIN);
Date dayStart= Date.from(date.atZone(ZoneId.systemDefault()).toInstant());
Output of CurrentCode: Fri Jul 09 00:00:00 UTC 2021
Current code picking servertime /GMT which is 5hrs ahead of CST.
Example: 09AM GMT is 14 CST/2PM CST
I have tried to set calendar to 00:00:00 and setTimeZone to America/New_York. But while am returning output as calendar.getTime() give some other time rather than giving CST 00:00:00.
Tried : #scheduled(zone="America/New_york" ) --Not Working.
There are two good answers. My suggestion only differs in the detail (which is where the devil is, according to some).
First of all you should avoid using the Date class if you can. You are already using java.time, the modern Java date and time API, (LocalDateTime, LocalTime, ZoneId). You are getting all the functionality that you need from java.time. So I am assuming that you are only converting to Date because you need a Date for some legacy API that you cannot afford to upgrade to java.time just now.
Instant startOfDay = ZonedDateTime.now(ZoneId.systemDefault())
.truncatedTo(ChronoUnit.DAYS)
.toInstant();
Date oldfashionedDate = Date.from(startOfDay);
System.out.println(oldfashionedDate);
.truncatedTo(ChronoUnit.DAYS) throws away the time part of the ZonedDateTime, usually leaving us with 00:00:00 on the same day in the same time zone.
Edit:
I want America Chicago time CDT
Running the above code with the default time zone of the JVM set to America/Chicago gave:
Mon Jul 12 00:00:00 CDT 2021
Getting the right Date value and getting the expected printed output are two different things since Date.toString() picks the default time zone of the JVM and uses it for rendering the string to be returned. This behaviour may give surprises. There is no way to persuade Date.toString() to use a different time zone, so the above output only comes through setting the default time zone.
Original text: There are a lot of time zones referred to as CST and there’s no way I can be sure which one you intended (and i believe that the comments stating that America/New_York is not one of them are correct). However, the only one that I could persuade the old-fashioned Date class to abbreviate CST was China Standard Time. Running the above code in Asia/Shanghai time zone gave this output:
Sat Jul 10 00:00:00 CST 2021
It looks right to me. Since you asked your question it has become Saturday 10th in China Standard Time time zone.
Any time zone will work for getting the right Date value, the start of the day in that time zone. You also wanted an abbreviation of CST in the printed output. Time zones that did not work for this include:
Australia/Adelaide time zone. Output was Sat Jul 10 00:00:00 ACST 2021. So even though Australian Central Standard Time is sometimes abbreviated just CST, Date chose ACST.
America/Havana. Cuba uses Cuba Daylight Time at this time of year, so CDT is output.
America/Winnipeg and American/Chicago. North American Central Time uses daylight saving time too, so here too CDT is output.
In any case, you know which time zone you intended, so I am leaving to you to pick.
The easiest way to change the timezone is to use System.setProperty("user.timezone", "America/New_York"); in Java NOTE:: America/New_York is not CST
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
class DateAndTimeZoneFormatter {
public static void main(String[] args) {
System.setProperty("user.timezone", "America/New_York");
LocalDateTime date = LocalDateTime.now().with(LocalTime.MIN);
Date dayStart = Date.from(date.atZone(ZoneId.systemDefault()).toInstant());
System.out.println(dayStart);
}
}
You could try to use a ZonedDateTime with a specific ZoneId:
public static void main(String[] args) {
// define the zone to be used
ZoneId americaChicago = ZoneId.of("America/Chicago");
// then take the date of today
ZonedDateTime nowInChicago = ZonedDateTime.of(
LocalDate.now(), // today
LocalTime.MIN, // start of day
americaChicago // zone
);
// define an output format
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("EEE MMM dd HH:mm:ss")
.appendLiteral(' ')
.appendZoneText(TextStyle.SHORT)
.appendLiteral(' ')
.appendPattern("uuuu")
.toFormatter(Locale.ENGLISH);
// then print the formatted String representation
System.out.println(nowInChicago.format(dtf));
}
This outputs
Fri Jul 09 00:00:00 CDT 2021
Downsides:
this won't fully match your expected output due to CST not being applied because it is daylight saving time. Therefore, CDT will be the output.
taking a Date.from this ZonedDateTime.toInstant() will affect the values:
Applying these two lines
Date sameNowInChicago = Date.from(nowInChicago.toInstant());
System.out.println(sameNowInChicago);
will output
Fri Jul 09 07:00:00 CEST 2021
on my machine because it is configured to have a ZoneId.of("Europe/Berlin"), which will be taken into account when printing a java.util.Date.
CEST ⇒ Central European Summer Time.
This question already has answers here:
Convert Java Date to UTC String
(7 answers)
Closed 5 years ago.
I set my Calendar instance to a UTC date at 00:00 however once i return the result its 1 hour ahead
Calendar cal = Calendar.getInstance(TIMEZONE_UTC, Locale.ENGLISH);
cal.set(2017, 12 - 1, 15);
cal.set(Calendar.AM_PM, Calendar.AM);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.println(cal.getTime());
// Fri Dec 15 01:00:00 CET 2017 but should be 00:00:00
I suppose there is the winter/summer offset but I didn't found any description in the Gregorian or Calendar Element to handle this issue
I am getting the impression that you are really after just the date of December 15, 2017, and just wanted to make sure that there is no unexpected hour-of-day? If so, LocalDate from java.time, the modern Java date and time API, is made for you:
LocalDate ld = LocalDate.of(2017, Month.DECEMBER, 15);
System.out.println(ld);
This prints
2017-12-15
No hours, minutes or seconds to be concerned about.
If you do need a date-time at 00:00 UTC (the time I used to call midnight until Basil Bourque’s comment), there are several ways to obtain it. One of them is:
OffsetDateTime utcDateTime = LocalDateTime.of(2017, Month.DECEMBER, 15, 0, 0)
.atOffset(ZoneOffset.UTC);
System.out.println(utcDateTime);
This prints
2017-12-15T00:00Z
The Z in the end means UTC or offset zero. You see that the time of day is 00:00 as you wanted.
The Calendar class that you used in the question is long outdated, so I recommend you don’t use it anymore. java.time, the modern Java date and time API also known as JSR-310, is so much nicer to work with.
What went wrong in your code?
While a Calendar does contain a time zone (you initialized it to TIMEZONE_UTC), a Date (another outdated class) doesn’t. So when you convert to Date using cal.getTime() you lose the information that you wanted the time to be in UTC. Next (and this confuses many), when you print the date, you implicitly call Date.toString(), and this method grabs your JVM’s time zone setting and produces a string with the time in this time zone. So apparently you are (like I am) in a time zone that is at UTC+01:00 in December. The following two date-times denote the same point on the timeline:
Fri Dec 15 01:00:00 CET 2017
Fri Dec 15 00:00:00 UTC 2017
The reason why you see local time printed is you're displaying it via an instance of Calendar using Date.toString() which uses the local timezone(implicitly use the system timezone).
I will get a Date like Sat May 31 16:38:17 GMT 2014. In DB also column has the same value. But when I will search for date like Sat May 31 16:30:00 GMT 2014 it wont search. But If I give less than 5:30 hours like Sat May 31 11:00:00 GMT 2014 . It works fine.
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone( "GMT-0:00" ));
cal.setTimeInMillis(inputDate.getTime());
cal.set(Calendar.MILLISECOND, 0);
inputDate = cal.getTime();
The underlying implementation of Date and Calendar both use the same system: a long representing milliseconds since 1st of January 1970, 0:00:00 GMT.
See Here for Date (lines 136 & 168) and HERE for Calendar (line 778)
So this gets us to this:
cal.setTimeInMillis(inputDate.getTime());
// this gets the long from the Date and puts it into the Calendar
// nothing is changed, you only get added functionality
// even if you change the Timezone this only affects how it is displayed
cal.set(Calendar.MILLISECOND, 0);
// the long is modified by setting the that represents only milliseconds to zero
inputDate = cal.getTime();
//the long is stored in a Date and returned
You get back a minimally altered Date object. Without the second instruction there would be no change at all.
This explains why nothing is converted, but not why the select doesn't work.
From the info you gave it seems there is a mismatch in the timezones of trinity of the DB, the JVM and your system.
Something in the line of this: your system is set to IST and your JVM somehow interprets your system time as GMT. To check this you could run System.out.println(new Date()). If it writes out the timezone as GTM but the numbers are the same as your systems clock (IST) then that is your problem.
You could also check:
do the time-stamps of an insert statement match with what arrives in the database
do the time-stamps of a database entry match the one you receive after a select
I created a Date object in Java. When I do so, it shows something like: date=Tue Aug 09 00:00:00 IST 2011. As a result, it appears that my Excel file is lesser by one day (27 feb becomes 26 feb and so on) I think it must be because of time. How can I set it to something like 5:30 pm?
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY,17);
cal.set(Calendar.MINUTE,30);
cal.set(Calendar.SECOND,0);
cal.set(Calendar.MILLISECOND,0);
Date d = cal.getTime();
Also See
Joda time
Calendar doc
Can you show code which you use for setting date object? Anyway< you can use this code for intialisation of date:
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2011-01-01 00:00:00")
I should like to contribute the modern answer. This involves using java.time, the modern Java date and time API, and not the old Date nor Calendar except where there’s no way to avoid it.
Your issue is very likely really a timezone issue. When it is Tue Aug 09 00:00:00 IST 2011, in time zones west of IST midnight has not yet been reached. It is still Aug 8. If for example your API for putting the date into Excel expects UTC, the date will be the day before the one you intended. I believe the real and good solution is to produce a date-time of 00:00 UTC (or whatever time zone or offset is expected and used at the other end).
LocalDate yourDate = LocalDate.of(2018, Month.FEBRUARY, 27);
ZonedDateTime utcDateDime = yourDate.atStartOfDay(ZoneOffset.UTC);
System.out.println(utcDateDime);
This prints
2018-02-27T00:00Z
Z means UTC (think of it as offset zero from UTC or Zulu time zone). Better still, of course, if you could pass the LocalDate from the first code line to Excel. It doesn’t include time-of-day, so there is no confusion possible. On the other hand, if you need an old-fashioned Date object for that, convert just before handing the Date on:
Date oldfashionedDate = Date.from(utcDateDime.toInstant());
System.out.println(oldfashionedDate);
On my computer this prints
Tue Feb 27 01:00:00 CET 2018
Don’t be fooled, it is correct. My time zone (Central European Time) is at offset +01:00 from UTC in February (standard time), so 01:00:00 here is equal to 00:00:00 UTC. It’s just Date.toString() grabbing the JVMs time zone and using it for producing the string.
How can I set it to something like 5:30 pm?
To answer your direct question directly, if you have a ZonedDateTime, OffsetDateTime or LocalDateTime, in all of these cases the following will accomplish what you asked for:
yourDateTime = yourDateTime.with(LocalTime.of(17, 30));
If yourDateTime was a LocalDateTime of 2018-02-27T00:00, it will now be 2018-02-27T17:30. Similarly for the other types, only they include offset and time zone too as appropriate.
If you only had a date, as in the first snippet above, you can also add time-of-day information to it:
LocalDate yourDate = LocalDate.of(2018, Month.FEBRUARY, 27);
LocalDateTime dateTime = yourDate.atTime(LocalTime.of(17, 30));
For most purposes you should prefer to add the time-of-day in a specific time zone, though, for example
ZonedDateTime dateTime = yourDate.atTime(LocalTime.of(17, 30))
.atZone(ZoneId.of("Asia/Kolkata"));
This yields 2018-02-27T17:30+05:30[Asia/Kolkata].
Date and Calendar vs java.time
The Date class that you use as well as Calendar and SimpleDateFormat used in the other answers are long outdated, and SimpleDateFormat in particular has proven troublesome. In all cases the modern Java date and time API is so much nicer to work with. Which is why I wanted to provide this answer to an old question that is still being visited.
Link: Oracle Tutorial Date Time, explaining how to use java.time.
If you don't have access to java 8 and the API java.time, here is my simple function to copy the time of one date to another date using the old java.util.Calendar (inspire by Jigar Joshi) :
/**
* Copy only the time of one date to the date of another date.
*/
public static Date copyTimeToDate(Date date, Date time) {
Calendar t = Calendar.getInstance();
t.setTime(time);
Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.HOUR_OF_DAY, t.get(Calendar.HOUR_OF_DAY));
c.set(Calendar.MINUTE, t.get(Calendar.MINUTE));
c.set(Calendar.SECOND, t.get(Calendar.SECOND));
c.set(Calendar.MILLISECOND, t.get(Calendar.MILLISECOND));
return c.getTime();
}
Calendar calendar = new Calendar.Builder()
.setDate(2022, Calendar.JUNE, 1)
.setTimeOfDay(0, 0, 0)
.build();
System.out.println(calendar.getTimeInMillis());
I have a Java Date that is from this summer during daylight savings time. For example:
Jun 01, 2009 06:00 AM PDT
My question is, how do I display this date as my local time zone and current daylight savings mode (in my case Pacific Standard Time)?
Jun 01, 2009 05:00 AM PST
Java's Date.toString() and SimpleDateFormat displays the date in the original daylight savings mode. Example:
System.out.println(new Date(1243861200000L));
outputs:
Mon Jun 01 06:00:00 PDT 2009
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
dateFormat.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println(dateFormat.format(new Date(1243861200000L)));
outputs:
Jun 01, 2009 06:00 AM PDT
What I really want to see is 5:00 AM PST (which is equivalent to 6:00 AM PDT). Is there a way to force it to use another daylight savings mode?
Follow up: By the way, this is the Windows XP behavior. A file created on June 1, 6 AM will be seen (by Explorer, Command Prompt, etc) as June 1, 5 AM during the winter.
I don't think there's a way to force the DateFormat to apply a TimeZone format to a time that couldn't exist. PST is only applicable in the Winter months and PDT is only used in the summer.
I formatted this date with all of the TimeZones returned by TimeZone.getAvailableIDs(), and found two that returned me PST for that particular time: Pacific/Pitcairn and SystemV/PST8. You could try using one of those, but I have no idea what other rules apply to either of those timezone objects.
If you're just concerned with getting the time with that offset, you could use GMT-8 as your TimeZone. However, that string will show up in your formatted date string instead of PST.
UPDATE: Here's a way to take any timezone and have it ignore all daylight savings time rules. You can grab a TimeZone object then grab another TimeZone.getTimeZone() object. On the second object set the Id and rawOffset to the corresponding object from the first TimeZone.
For example:
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
TimeZone defaultTimeZone = TimeZone.getDefault();
TimeZone timeZone = TimeZone.getTimeZone("");
timeZone.setID(defaultTimeZone.getID());
timeZone.setRawOffset(defaultTimeZone.getRawOffset());
dateFormat.setTimeZone(timeZone);
System.out.println(dateFormat.format(new Date(1243861200000L)));
This will print out exactly what you're looking for.
PST/PDT change throughout the year. Java attempts to determine which one is in affect on a given date. This things obviously change as the laws and regions change. Can you use an absolute time zone? Specifying the offset in GMT will be the same year around.
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT-07:00"));
System.out.println(dateFormat.format(new Date(1243861200000L)));
Jun 01, 2009 06:00 AM GMT-07:00
this might do the trick:
/*
* Create a date that represents 1,243,861,200,000 milliseconds since
* Jan 1, 1970
*/
Date date = new Date(1243861200000L);
/*
* Print out the date using the current system's default format and time
* zone. In other words, this will print differently if you set the
* operating zone's time zone differently.
*/
System.out.println(date);
/*
* Specify the format and timezone to use
*/
DateFormat dateFormat = new SimpleDateFormat(
"MMM dd, yyyy hh:mm aa zzz");
TimeZone pstTZ = TimeZone.getTimeZone("PST");
dateFormat.setTimeZone(pstTZ);
System.out.println(dateFormat.format(date));
/*
* It looks like what you want is to actually display a different date
* (different # milliseconds since epoch) in the summer months. To do that, you
* need to change the date by subtracting an hour.
*/
if(pstTZ.inDaylightTime(date)){
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR, -1);
date = cal.getTime();
}
//now this should always print "5:00". However, it will show as 5:00 PDT in summer and 5:00 PST in the winter which are actually 2 different dates. So, I think you might need to think about exactly what it is you're trying to achieve.
System.out.println(dateFormat.format(date));
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy hh:mm aa zzz");
dateFormat.setTimeZone(TimeZone.getTimeZone("Pacific/Pitcairn"));
System.out.println(dateFormat.format(new Date(1243861200000L)));
Additional comments: zzz will print out PST, while z will print out GMT-08:00. TimeZone.getTimeZone("EST") works for for Eastern Standard Time, making me think this is a bug with TimeZone.getTimeZone("PST").
I suggest using predefined time zones, since they can be confusing:
public static final TimeZone ZONE_GREENWICH_MEAN_TIME = TimeZone.getTimeZone("GMT");
public static final TimeZone ZONE_EASTERN_DAYLIGHT_TIME = TimeZone.getTimeZone("America/New_York"); // EDT, GMT-04:00
public static final TimeZone ZONE_EASTERN_STANDARD_TIME = TimeZone.getTimeZone("EST"); // GMT-05:00
public static final TimeZone ZONE_PACIFIC_DAYLIGHT_TIME = TimeZone.getTimeZone("America/Los_Angeles"); // PDT, GTM-0700
public static final TimeZone ZONE_PACIFIC_STANDARD_TIME = TimeZone.getTimeZone("Pacific/Pitcairn"); // PST, GMT-08:00
I came across another time with a similar problem "2009-11-01 08:44:44". I tried iterating over all IDs and none would print EDT. The funny thing was that "2010-11-01 08:44:44" would print EDT. Between 1990 and 2010, only 2007, 2008 and 2010 would print EDT. When I checked the years from 0 to 2499, only 431 had EDT, with the first in 1940 (this must be when EDT was introduced). So of the 560 years (1940-2499), only 431 have an ID that prints EDT. From 1940 to 2006, there are only 10 years which have IDs which print EDT. After 2006, every 4, 5 or 10 years, there is a year which will not print EDT.