Why inDaylightTime() method returning wrong in timezone? - java

My first print shows that daylight saving starts from 8th March, whereas to check that I have passed my custom date(9th March) to timeZone.inDaylightTime(calendar.getTime()), whereas it is returning false.Where I am going wrong ?
TimeZone timeZone = TimeZone.getTimeZone("US/Eastern");
System.out.println("TimeZone ::: "+timeZone);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.AM_PM, Calendar.AM);
calendar.set(Calendar.MONTH, Calendar.MARCH);
calendar.set(Calendar.DAY_OF_MONTH, 9);
calendar.set(Calendar.YEAR,2019);
boolean b = timeZone.inDaylightTime(calendar.getTime());
System.out.println("Is the day in daylight saving "+b);

DST wasn't in effect in the U.S. Eastern zone on March 9th, 2019. It went into effect March 10th at 2 a.m. See timeanddate.com.
My first print shows that daylight saving starts from 8th March...
I'm guessing you're basing that on this:
startMode=3,
startMonth=2,
startDay=8,
startDayOfWeek=1,
startTime=7200000
Remember that DST changes (in the U.S. at least) always happen early on a Sunday morning. What that rule says is that the first Sunday on or after March 8th is when the change should occur, not that it should occur on March 8th (which was a Friday). The law says it starts the second Sunday in March (at the moment, it's varied periodically), so by saying the first Sunday on or after March 8th, the code fits the definition "second Sunday of March."
You can see this concept in the description of SimpleTimeZone:
To construct a SimpleTimeZone with a daylight saving time schedule, the schedule can be described with a set of rules, start-rule and end-rule. A day when daylight saving time starts or ends is specified by a combination of month, day-of-month, and day-of-week values. The month value is represented by a Calendar MONTH field value, such as Calendar.MARCH. The day-of-week value is represented by a Calendar DAY_OF_WEEK value, such as SUNDAY. The meanings of value combinations are as follows.
Exact day of month
To specify an exact day of month, set the month and day-of-month to an exact value, and day-of-week to zero. For example, to specify March 1, set the month to MARCH, day-of-month to 1, and day-of-week to 0.
Day of week on or after day of month
To specify a day of week on or after an exact day of month, set the month to an exact month value, day-of-month to the day on or after which the rule is applied, and day-of-week to a negative DAY_OF_WEEK field value. For example, to specify the second Sunday of April, set month to APRIL, day-of-month to 8, and day-of-week to -SUNDAY.
Day of week on or before day of month
To specify a day of the week on or before an exact day of the month, set day-of-month and day-of-week to a negative value. For example, to specify the last Wednesday on or before the 21st of March, set month to MARCH, day-of-month is -21 and day-of-week is -WEDNESDAY.
Last day-of-week of month
To specify, the last day-of-week of the month, set day-of-week to a DAY_OF_WEEK value and day-of-month to -1. For example, to specify the last Sunday of October, set month to OCTOBER, day-of-week to SUNDAY and day-of-month to -1.

could you please post a small example by using those ZoneId and
ZonedDateTime to get dayLightSaving date exists
It’ll be my pleasure.
ZoneId zone = ZoneId.of("America/New_York");
ZonedDateTime testTime = ZonedDateTime.of(2019, 3, 9, 0, 0, 0, 0, zone);
boolean dst = zone.getRules().isDaylightSavings(testTime.toInstant());
System.out.println("Is the day in daylight saving " + dst);
Is the day in daylight saving false
As stated in the other answer, summer time (DST) began last Sunday, March 10, in North America this year. So let’s try with that day at 5 AM — then we should get true.
ZonedDateTime testTime = ZonedDateTime.of(2019, 3, 10, 5, 0, 0, 0, zone);
Is the day in daylight saving true
zone.getRules() returns a ZoneRules object. Such an object knows everything about the UTC offset for the time zone, also about DST. So we can query it with an Instant. We get an Instant from testTime.toInstant().
Link: Section Time Zone and Offset Classes in the Oracle tutorial (including an example of using ZoneRules that somewhat resembles mine).

Related

How to mock datetime with java.time.clock?

Why the date generated with below code offset the given time to 11:00:00.00?
test("shouldReturnGivenMockedDateTime") {
val mockedDateTime = "2020-01-01T10:00:00.00Z"
val clock: Clock = Clock.fixed(Instant.parse(mockedDateTime), TimeZone.getDefault.toZoneId);
val result = LocalDateTime.ofInstant(clock.instant, TimeZone.getDefault.toZoneId)
assert(result.toString == "2020-01-01T10:00") // FALSE!!!
assert(result.toString == "2020-01-01T11:00") // TRUE
}
Why the date generated with below code offset the given time to
11:00:00.00?
Your mock date is 1st January, 2020. According to your link, Belgrade was at offset UTC+1h on this date. From 27th October 2019 until 29th March 2020, more precisely. The mocked date and time is also in UTC, denoted by the trailing Z. When querying the time in your local time zone, Europe/Belgrade, 1 hour is added to the UTC time, so 10:00 becomes 11:00.
You are correct, of course, that Belgrade is at offset +02:00 here in May (because of summer time/DST). Only when converting a date and time in January, the offset that was valid back then is used, not the offset for May.
Repeating your link: 2020 Time Zones - Belgrade

Javas GregorianCalendar.toZonedDateTime() returns different date for dates in the past

For some date in the past, GregorianCalendar.toZonedDateTime() returns a date that is 1 day off.
For 2nd April 1893, toZonedDateTime() returns the same date, for 1st April 1893, ZonedDateTime shows me the 31st March 1893 and there is also a difference in the "day of the year" values. There is always an offset for dates before this "magic" date.
Here is some sample code:
final GregorianCalendar gc = new GregorianCalendar(1893, 0, 1); // Set to 1st January 1893
for(int i = 1; i < 365; i++) {
gc.set(Calendar.DAY_OF_YEAR, i); // Update day of year
final ZonedDateTime zdt = gc.toZonedDateTime();
System.out.println(String.format(
"GC: %02d.%02d.%d (%d) -> ZDT: %02d.%02d.%d (%d)",
gc.get(Calendar.DAY_OF_MONTH),
gc.get(Calendar.MONTH) + 1, // "+1" is needed, because GregorianCalendar encodes January as 0.
gc.get(Calendar.YEAR),
gc.get(Calendar.DAY_OF_YEAR),
zdt.getDayOfMonth(),
zdt.getMonthValue(),
zdt.getYear(),
zdt.getDayOfYear()
));
}
When running the code, you will get the output
[...]
GC: 31.03.1893 (90) -> ZDT: 30.03.1893 (89)
GC: 01.04.1893 (91) -> ZDT: 31.03.1893 (90)
GC: 02.04.1893 (92) -> ZDT: 02.04.1893 (92)
GC: 03.04.1893 (93) -> ZDT: 03.04.1893 (93)
[...]
What am I doing wrong here?
Thanks in advance for your answers!
Best regards,
Markus
What is your system timezone?
I suspect you may be in a locale which observes, or observed, a DST type change on the 1st April 1893. Try printing out the offset value of the ZonedDateTime at each iteration of your loop.
Or a little more info can be gleaned by removing the timezone factor LocalDateTime.ofInstant(zdt.toInstant(), ZoneOffset.UTC)
Seems this is related to Berlin choosing to adopt CET on that date
The tzdata file europe contains only one zone Europe/Berlin for all of Germany.
It is not the best possible choice for several reasons:
- Berlin started CET only in 1893, later than several southern states.
https://mm.icann.org/pipermail/tz/2011-August/008736.html
From the JavaDocs of GregorianCalendar:
public ZonedDateTime toZonedDateTime()
Converts this object to a ZonedDateTime that represents the same point on the time-line as this GregorianCalendar.
Since this object supports a Julian-Gregorian cutover date and ZonedDateTime does not, it is possible that the resulting year, month and day will have different values. The result will represent the correct date in the ISO calendar system, which will also be the same value for Modified Julian Days.
I think it is some kind of non-desired but expected behaviour.
I suspect it’s a bug in GregorianCalendar. I have before seen bugs in Date for dates before 1900 in certain time zones. I consider ZonedDateTime and the other classes from java.time solider and more trustworthy.
Berlin was at offset +0:53:28 until April 1, 1893 00:00. At day of year 89 (for the sake of an example) your code gives a ZonedDateTime of 1893-03-29T23:53:28+00:53:28[Europe/Berlin] giving the correct offset. But both your GregorianCalendar and your ZonedDateTime represent a moment of 1893-03-29T23:00:00Z (UTC), so the GregorianCalendar seems to have assumed an offset of +01:00 instead, which is wrong. The conversion converts the moment correctly (and also the time zone correctly) and therefore the individual date and time fields incorrectly.
Source: For the offset for Berlin up until 1893 go to Time Zone in Berlin, Germany on timeanddate.com. Under “Time Changes in Berlin Over the Years”, in the dropdown on the top right select “1850 — 1899”. For the years 1850–92 you will see “No changes, UTC +0:53:28 hours all of the period”, and a change on April 1, 1893 at 00:00 to CET/UTC +1.
Here’s what I tried within your loop:
System.out.println(gc.getTimeZone().getID());
System.out.println(gc.getTime());
System.out.println(Instant.ofEpochMilli(gc.getTimeInMillis()));
System.out.println();
final ZonedDateTime zdt = gc.toZonedDateTime();
System.out.println(zdt);
System.out.println(zdt.toInstant());
Output for day of year (i) 89 was:
Europe/Berlin
Thu Mar 30 00:00:00 CET 1893
1893-03-29T23:00:00Z
1893-03-29T23:53:28+00:53:28[Europe/Berlin]
1893-03-29T23:00:00Z

Why does java.util.Calendar return minimal WEEK_OF_MONTH value as zero?

I'm trying to set minimal value of WEEK_OF_MONTH field as follows:
calendar.set(WEEK_OF_MONTH, calendar.getActualMinimum(WEEK_OF_MONTH));
The call to
calendar.getActualMinimum(WEEK_OF_MONTH)
returns 0
But at calculation during get* operations this field becomes 5.
Moreover, without leniency mode, I get
java.lang.IllegalArgumentException: WEEK_OF_MONTH: 0 -> 5 // or MONTH: 9 -> 8
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2829)
at java.util.Calendar.updateTime(Calendar.java:3393)
at java.util.Calendar.complete(Calendar.java:2265)
at java.util.Calendar.get(Calendar.java:1826)
at Main.main(Main.java:19)
If I set WEEK_OF_MONTH = 1, then I get it correctly as 1.
Check out an example
Can anyone clarify such a behavior? Thanks in advance.
java.time
Locale russia = Locale.forLanguageTag("ru-RU");
WeekFields wf = WeekFields.of(russia);
LocalDate date = LocalDate.now(ZoneId.of("Europe/Moscow"));
int minimumWeekOfMonth = date.with(TemporalAdjusters.firstDayOfMonth()).get(wf.weekOfMonth());
System.out.println("Minimum week of month: " + minimumWeekOfMonth);
LocalDate dateInFirstWeekOfMonth = date.with(wf.weekOfMonth(), minimumWeekOfMonth);
System.out.println("Date in first week of month: " + dateInFirstWeekOfMonth);
When running this snippet just now I got the following output:
Minimum week of month: 1
Date in first week of month: 2018-10-05
I have assumed that you are in Russian locale. Russia uses the international week numbering where Monday is the first day of the week and week one of a year or month is the first week that contains at least 4 days of the year or month. So week 1 of October 2018 was from Monday October 1 through Sunday October 7. This in turn means that the minumum week in this month is 1. Starting out from today (a Friday) and setting the week of month to 1 gives Friday in week 1, that is, Friday October 5.
If I start out from Wednesday September 12 instead I get:
Minimum week of month: 0
Date in first week of month: 2018-08-29
Week 1 of September was from Monday September 3 through September 9. This means that September 1 and 2 were in week 0, so 0 is the minimum week of month for September. And when starting from a Wednesday I set week number to 0, I get the Wednesday of that week, which happens to lie in August: August 29. If we ask for the week of month of that date, do we get 0?
System.out.println("Week of month: " + dateInFirstWeekOfMonth.get(wf.weekOfMonth()));
Output:
Week of month: 5
Since the date is in August, we now get which week of August the date is in, which happens to be week 5.
What happened in your code?
It seems to me that GregorianCalendar.getActualMinimum(Calendar.WEEK_OF_MONTH) always returns 0. I cannot make sense of this observation. Since Russia uses the Gregorian calendar, an instance of GregorianCalendar is what you really get from Calendar.getInstance.
I wouldn’t want to bother. As I said in a comment already, the Calendar class is long outdated and has a range of design problems with it, so I recommend you don’t use it. I’d certainly prefer java.time, the modern Java date and time API, any time.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Week-based pattern does not work as expected

I expect these two formatters to be equivalent:
DateTimeFormatter fromBuilder = new DateTimeFormatterBuilder()
.appendValue(IsoFields.WEEK_BASED_YEAR, 4)
.appendLiteral('-')
.appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
.toFormatter();
DateTimeFormatter fromPattern = DateTimeFormatter.ofPattern("YYYY-ww");
But they do not give the same result:
LocalDate date = LocalDate.of(2017, 1, 1);
System.out.printf("from builder: %s%n", fromBuilder.format(date)); // prints 'from builder: 2016-52'
System.out.printf("from pattern: %s%n", fromPattern.format(date)); // prints 'from pattern: 2017-01'
What am I missing?
The Y and w patterns correspond to a localized version of week-fields, using the JVM's default locale (java.util.Locale). The second formatter is equivalent to:
// localized week fields (using default Locale)
WeekFields weekFields = WeekFields.of(Locale.getDefault());
// equivalent to YYYY-ww
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
.appendValue(weekFields.weekBasedYear(), 4)
.appendLiteral('-')
.appendValue(weekFields.weekOfWeekBasedYear(), 2)
.toFormatter();
As this is locale dependent, it can or can't work like IsoFields. The WeekFields created above will have a different behaviour depending on the JVM's default locale.
IsoFields, on the other hand, follows ISO-8601 definition to define the week-based fields, as described in the javadoc:
The first week of a week-based-year is the first Monday-based week of the standard ISO year that has at least 4 days in the new year.
If January 1st is Monday then week 1 starts on January 1st
If January 1st is Tuesday then week 1 starts on December 31st of the previous standard year
If January 1st is Wednesday then week 1 starts on December 30th of the previous standard year
If January 1st is Thursday then week 1 starts on December 29th of the previous standard year
If January 1st is Friday then week 1 starts on January 4th
If January 1st is Saturday then week 1 starts on January 3rd
If January 1st is Sunday then week 1 starts on January 2nd
As 2017-01-01 is a Sunday, it corresponds to the last line above: week 1 starts on January 2nd 2017, so January 1st 2017 is still in the last week of 2016.
You can check how your WeekFields instance differs from IsoFields by calling the methods getFirstDayOfWeek() and getMinimalDaysInFirstWeek() - which are used to calculate the values of the respecitive week-based fields:
A week is defined by:
The first day-of-week. For example, the ISO-8601 standard considers Monday to be the first day-of-week.
The minimal number of days in the first week. For example, the ISO-8601 standard counts the first week as needing at least 4 days.
Together these two values allow a year or month to be divided into weeks.
In the JVM I'm using, the default locale is pt_BR, and the WeekFields created has the first day-of-week as Sunday, and minimal days in first week as 1. Check yours and you'll see that it also differs from IsoFields.
You can check ISO's definition by using the constant WeekFields.ISO: getFirstDayOfWeek() returns Monday and getMinimalDaysInFirstWeek() returns 4.
Also, remind that there's a small difference between IsoFields and WeekFields.ISO. Quoting JodaStephen's comment in this thread:
The only observable difference was that WeekFields operates on all calendar systems (by converting to ISO) whereas IsoFields only operates on ISO (and rejects other calendar systems)

Calendar Month Instance is off by one

Here is my code:
Month is passed in on a loop. First 0 (since it is January as I type), then 1, and so on. Next month when it is February, this loop will start from that date. 1, 2, etc.
int thisMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
cal = Calendar.getInstance();
df = new SimpleDateFormat("MMM yyyy", Locale.ENGLISH);
cal.set(Calendar.MONTH, month + thisMonth);
String sMonth = df.format(cal.getTime());
In the first loop, sMonth is March 2015.
In the second loop, sMonth is March 2015.
In the third loop, sMonth is April 2015.
In the fourth loop, sMonth is May 2015.
..and so on
As you see, the first month is NOT February as expected. I believe it is January 29th so that may have some cause as we are so close to February. But if that is the case, why would this happen twice?
I know since I am not working with unix timestamps things aren't exact, is there away to calculate this where I can at least get accurate month ordering?
Since today is the 30th, you're getting the current date (2015-01-30), and incrementing the month to get 2015-02-30 - which "rolls over" to 2015-03-02 since February doesn't have 30 days.
One way to avoid this problem is to set the day-of-month to 1 before changing the month.

Categories

Resources