I am trying to find how DST works,for that I have written sample of code which talks about DST,I wonder why TimeZone changes at 1:00AM as per my understanding DST end 03 November 2013 at 2:00AM so at 2:00AM it should give 1:00AM then TimeZone should be chnaged, but its not like that. Can anyone help me out of this...
public static void main(String[] args) throws InterruptedException
{
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
DateFormat fmt = new SimpleDateFormat("dd-MM-yy HH:mm:ss zz");
Calendar cal = Calendar.getInstance();
cal.set(2013, 10, 03, 0, 59, 59);
System.out.println(fmt.format(cal.getTime()));
cal.set(2013, 10, 03, 1, 0, 0);
System.out.println(fmt.format(cal.getTime()));
}
Output:
03-11-13 00:59:59 PDT
03-11-13 01:00:00 PST
01:00 happens twice, once in PDT and once (an hour later) in PST.
If you tell the Calendar that it is 01:00 on a date of time change, then the class identifies that your input corresponds to 2 distinct possible times, and arbitrarily uses one of them.
#Andrew Spencer is right, 1:00 a.m. has two possibilities, and Calendar picked one of them, just not the one you were expecting. If you want to see 1:00 AM PDT, then just add a minute to 12:59 AM:
public static void main(String[] args) throws InterruptedException {
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
DateFormat fmt = new SimpleDateFormat("dd-MM-yy HH:mm:ss zz");
Calendar cal = Calendar.getInstance();
cal.set(2013, 10, 03, 0, 59, 59);
System.out.println(fmt.format(cal.getTime()));
cal.add(Calendar.MINUTE, 1); // this will still be in PDT
System.out.println(fmt.format(cal.getTime()));
}
If I understand you correctly you wonder why 03-11-13 01:00:00 is PST? I think you explained this yourself. If 2:00 actually has to be moved to 1:00, so 1:00 is already daylight saving time, i.e. PST.
Related
This question already has answers here:
Why when year is less than 1884, it remove few milliseconds?
(2 answers)
Closed 3 years ago.
This is not a duplicate as some people think. It is about two standard Java classes for formatting dates that produce different strings for the same value of milliseconds since the epoch.
For values of milliseconds since the epoch that occur before some point in the year 1883, SimpleDateFormat and DateTimeFormatter will produce different results. For reasons I don't understand, DateTimeFormatter will produce strings that differ from what I expect by almost four minutes.
This is important because I am changing some code to use DateTimeFormatter instead of SimpleDateFormat. Our input is always milliseconds since the epoch, and I need the values to be the same after I change the code.
The previous code would create a Date from the milliseconds, then use SimpleDateFormat to format it.
The new code creates an Instant from the milliseconds, then a ZonedDateTime from the Instant, then a DateTimeFormatter to format it.
Here's a test I wrote using JUnit4 and Hamcrest. The test finds the milliseconds since the epoch for May 13, 15:41:25, for each year starting at 2019 and working backwards one year at a time.
For each year, it formats the milliseconds using SimpleDateFormat and DateTimeFormatter then compares the results.
#Test
public void testSimpleDateFormatVersusDateTimeFormatter() throws Exception {
String formatString = "EEE MMM dd HH:mm:ss zzz yyyy";
String timeZoneCode = "America/New_York";
ZoneId zoneId = ZoneId.of(timeZoneCode);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(formatString);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(timeZoneCode));
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatString);
for (int year = 0; year < 200; year++) {
long millis = getMillisSinceEpoch(2019 - year, 5, 13, 15, 41, 25, timeZoneCode);
System.out.printf("%s%n", new Date(millis));
// Format using a DateTimeFormatter;
Instant instant = Instant.ofEpochMilli(millis);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId);
String dateTimeFormatterString = dateTimeFormatter.format(zonedDateTime);
// Format using a SimpleDateFormat
Date date = new Date(millis);
String simpleDateFormatString = simpleDateFormat.format(date);
System.out.println("dateTimeFormatterString = " + dateTimeFormatterString);
System.out.println("simpleDateFormatString = " + simpleDateFormatString);
System.out.println();
assertThat(simpleDateFormatString, equalTo(dateTimeFormatterString));
}
}
private long getMillisSinceEpoch(int year, int month, int dayOfMonth, int hours, int minutes, int seconds, String timeZoneId) {
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
Calendar calendar = Calendar.getInstance(timeZone);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month-1);
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
calendar.set(Calendar.HOUR_OF_DAY, hours);
calendar.set(Calendar.MINUTE, minutes);
calendar.set(Calendar.SECOND, seconds);
return calendar.getTimeInMillis();
}
Running this you can see it passes for all years from 2019 back to 1884. So for any given year you see output like this:
Mon May 13 12:41:25 PST 1895
dateTimeFormatterString = Mon May 13 15:41:25 EST 1895
simpleDateFormatString = Mon May 13 15:41:25 EST 1895
But once it gets to 1883 it inexplicably fails:
Sun May 13 12:41:25 PST 1883
dateTimeFormatterString = Sun May 13 15:45:23 EST 1883
simpleDateFormatString = Sun May 13 15:41:25 EST 1883
java.lang.AssertionError:
Expected: "Sun May 13 15:45:23 EST 1883"
but: was "Sun May 13 15:41:25 EST 1883"```
The hours and seconds are obviously wrong.
By the way, if I change the time zone to "UTC", then the test passes.
According to https://www.timeanddate.com/time/change/usa/new-york?year=1883 (which was the first hit in a Google search for "1883 time adjustment"):
Nov 18, 1883 - Time Zone Change (LMT → EST)
When local standard time was about to reach
Sunday, November 18, 1883, 12:03:58 pm clocks were turned backward 0:03:58 hours to
Sunday, November 18, 1883, 12:00:00 noon local standard time instead.
3:58 matches the "almost four minutes" that you're seeing.
I haven't tested this, but I bet that if you iterate through months and days in addition to years, it occurs at that date.
See Also
Why when year is less than 1884, it remove few milliseconds?
Python pytz timezone conversion returns values that differ from timezone offset for different dates
Why is subtracting these two times (in 1927) giving a strange result? — a classic answered by Jon Skeet; not the same issue, but the same kind of issue
The Times Reports on "the Day of Two Noons"
This question already has answers here:
How to create a Java Date object of midnight today and midnight tomorrow?
(20 answers)
Closed 6 years ago.
I want to round a java.util.Date object to the end of the day, e.g. rounding 2016-04-21T10:28:18.109Z to 2016-04-22T00:00:00.000Z.
I saw Java Date rounding, but wasn't able to find something compareable for the end of the day. It also is not the same as how to create a Java Date object of midnight today and midnight tomorrow?, because I don't want to create a new Date (midnight today or tomorrow), but the next midnight based on any given date.
The DateUtils.ceiling serves your purpose. Pass Calendar.DATE for field value.
Given the documentation of DateUtils, I'm not sure I'd trust it with this.
Assuming you're only interested in a UTC day, you can take advantage of the fact that the Unix epoch is on a date boundary:
public static Date roundUpUtcDate(Date date) {
long millisPerDay = TimeUnit.DAYS.toMillis(1);
long inputMillis = date.getTime();
long daysRoundedUp = (inputMillis + (millisPerDay - 1)) / millisPerDay;
return new Date(daysRoundedUp * millisPerDay);
}
I would strongly urge you to move to the java.time API if you possibly can though.
Traditional way
#Test
public void testDateRound() throws ParseException {
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse("2016-04-21T10:28:18.109Z");
System.out.println(date);
Calendar cl = Calendar.getInstance();
cl.setTime(date);
cl.set(Calendar.HOUR_OF_DAY, 23);
cl.set(Calendar.MINUTE, 59);
cl.set(Calendar.SECOND, 59);
cl.set(Calendar.MILLISECOND, 999);
System.out.println(cl.getTime());
cl.add(Calendar.MILLISECOND, 1);
System.out.println(cl.getTime());
}
Output
Thu Apr 21 10:28:18 GMT+03:00 2016
Thu Apr 21 23:59:59 GMT+03:00 2016
Fri Apr 22 00:00:00 GMT+03:00 2016
I am trying to change DayofWeek in Calendar but doesnt appear to be working as I expect. Here is an example. I set calendar time to a Friday time, but when I set Calendar.DAY_OF_WEEK to Calendar.SUNDAY, it is moving forward to next week. Since Calendar.SUNDAY is first day of week by default, shouldn't it move the time back to beginning of current week?
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class GenericWeekdayOpenFunction implements TimePeriodFunction {
public static void main(String[] args) {
// Nov 8 is Friday
long time = DateUtilities.newDateTimeAsMillis(2013, 11, 8, 10, 00, 00);
System.out.println(DateUtilities.formatGmtDatetime(time));
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
calendar.setTimeInMillis(time);
// move day of week to Sunday, expect date to be Nov 3
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(DateUtilities.formatGmtDatetime(calendar.getTimeInMillis())); // wrong
// move day of week to Friday, expect date to be Nov 8
calendar.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(DateUtilities.formatGmtDatetime(calendar.getTimeInMillis()));
}
}
Output:
08-11-2013 10:00:00.000
10-11-2013 10:00:00.000
08-11-2013 10:00:00.000
Your scenario working fine with basic Calendar class usage:
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Date d = new Date(113, 10, 8, 10, 0, 0);
c.setTimeInMillis(d.getTime());
System.out.println(c.getTime());
c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(c.getTime());
c.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(c.getTime());
Output:
Fri Nov 08 10:00:00 IST 2013
Sun Nov 03 10:00:00 IST 2013
Fri Nov 08 10:00:00 IST 2013
Note that Date(113, 10, 8, 10, 0, 0); is used only for quick check, it is deprecated though. Trying for any other combination also works fine. Can you just try using basic Calendar API and print dates ie
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
System.out.println(c.getTime());//current day
c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(c.getTime());
second date should go back to previous sunday not upcoming one. If it's working for you then DateUtilities implementation may be doubtful.
I think that the method set(int field, int value)
Works approaching to the nearest day (not to the DAY_OF_WEEK of the same week).
But you can use the function add(int field, int amount) in this case add(Calendar.DATE, -5) to do that.
I have following method which convert my custom DMY (date,month,year) object to Date.
public static Date serverCreateDateFromDMY(DMY pDMY, TimeZone pTimeZone)
{
Calendar vCalendar = Calendar.getInstance(pTimeZone);
vCalendar.set(Calendar.YEAR, pDMY.getYear());
// Below line is because DMY month counts are 1-indexed
// and Date month counts are 0-indexed
vCalendar.set(Calendar.MONTH, pDMY.getMonthOfYear() - 1);
vCalendar.set(Calendar.DAY_OF_MONTH, pDMY.getDayOfMonth());
System.out.println(vCalendar.getTime());
TimeUtilsServer.zeroCalendarHoursAndBelow(vCalendar);
System.out.println(vCalendar.getTime());
return vCalendar.getTime();
}
public static void zeroCalendarHoursAndBelow(Calendar pToZero)
{
pToZero.set(Calendar.HOUR_OF_DAY, 0);
pToZero.set(Calendar.MINUTE, 0);
pToZero.set(Calendar.SECOND, 0);
pToZero.set(Calendar.MILLISECOND, 0);
}
to serverCreateDateFromDMY() method, I am passing these arguments : DMY=20120424, and TimeZone is : America/New_York. Application is running locally in my timezone which is IST.
based in above inputs, following output is printed.
Tue Apr 24 14:43:07 IST 2012
Tue Apr 24 09:30:00 IST 2012
so as you see that in last output time is not zeroed out. any suggestions please?
#Marko, yes I come to know about DateFormat and I tried following example. but still date is printed with time and not zeroing out.
TimeZone tz = TimeZone.getTimeZone("America/New_York");
Calendar vCalendar = Calendar.getInstance(tz);
vCalendar.set(Calendar.YEAR, 2012);
vCalendar.set(Calendar.MONTH, 4 - 1);
vCalendar.set(Calendar.DAY_OF_MONTH, 24);
DateFormat df = DateFormat.getDateTimeInstance();
df.setTimeZone(tz);
System.out.println(df.format(vCalendar.getTime()));
vCalendar.set(Calendar.HOUR_OF_DAY, vCalendar.getActualMinimum(Calendar.HOUR_OF_DAY));
vCalendar.set(Calendar.MINUTE, vCalendar.getActualMinimum(Calendar.MINUTE));
vCalendar.set(Calendar.SECOND, vCalendar.getActualMinimum(Calendar.SECOND));
vCalendar.set(Calendar.MILLISECOND, vCalendar.getActualMinimum(Calendar.MILLISECOND));
System.out.println(df.format(vCalendar.getTime()));
java Date / Time API have a bad design from the time of its creation. Maybe you should take a look at some library - for example this which hides JDK API deficiencies - http://joda-time.sourceforge.net/
Internally, Date and Calendar objects are stored in UTC. When you set the fields to 0, the Calendar is updated in UTC.
When you ask the Calendar for the time, it then converts the Date to your desired Timezone, hence the difference.
... and you are 9:30h ahead of NY time. You set the time to midnight NY time and read it out as time in your zone. Note that getTime returns a Date, which is not timezone-configurable. You'll need DateFormat if you want to specify the timezone for which you print the result.
I have the start date and the end date. I need to iterate through every day between these 2 dates.
What's the best way to do this?
I can suggest only something like:
Date currentDate = new Date (startDate.getTime ());
while (true) {
if (currentDate.getTime () >= endDate.getTime ())
break;
doSmth ();
currentDate = new Date (currentDate.getTime () + MILLIS_PER_DAY);
}
ready to run ;-)
public static void main(String[] args) throws ParseException {
GregorianCalendar gcal = new GregorianCalendar();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
Date start = sdf.parse("2010.01.01");
Date end = sdf.parse("2010.01.14");
gcal.setTime(start);
while (gcal.getTime().before(end)) {
gcal.add(Calendar.DAY_OF_YEAR, 1);
System.out.println( gcal.getTime().toString());
}
}
Ditto on those saying to use a Calendar object.
You can get into surprising trouble if you try to use a Date object and add 24 hours to it.
Here's a riddle for you: What is the longest month of the year? You might think that there is no answer to that question. Seven months have 31 days each, so they are all the same length, right? Well, in the United States that would be almost right, but in Europe it would be wrong! In Europe, October is the longest month. It has 31 days and 1 hour, because Europeans set their clocks back 1 hour for Daylight Saving Time in October, making one day in October last 25 hours. (Americans now begin DST in November, which has 30 days, so November is still shorter than October or December. Thus making that riddle not as amusing for Americans.)
I once ran into trouble by doing exactly what you're trying to do: I used a Date object and added 24 hours to it in a loop. It worked as long as I didn't cross Daylight Saving Time boundaries. But when I did, suddenly I skipped a day or hit the same day twice, because Midnight March 8, 2009 + 24 hours = 1:00 AM March 10. Drop off the time, as I was doing, and March 9 was mysteriously skipped. Likewise midnight Nov 1, 2009 + 24 hours = 11:00 PM Nov 1, and we hit Nov 1 twice.
Use a Calendar object if you want to manipulate dates.
Calendar c = Calendar.getInstance();
// ... set the calendar time ...
Date endDate = new Date();
// ... set the endDate value ...
while (c.getTime().before(endDate) {
// do something
c.add(Calendar.DAY_OF_WEEK, 1);
}
Or use Joda Time
I highly recommend using Joda time:
Java Joda Time - Implement a Date range iterator