Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java.util.Calendar - Year 1947

Tags:

java

I found an interesting behavior in WSO2 platform using Calendar to convert String to Date. WSO2 uses java.util.Calendar as the final result. I found that if a date from 01.01.1947 - 23.02.1947 is used in code snippet bellow the result always gives us one day before. I found out that its our Timezone doing this as it is one hour forward. Meaning Calendar decreases result one hour backwards and we get the day before 11PM.

We did already solve the problem by not converting to Date. So that is not the issue.

The question is, why is this happening only for dates 01.01.1947 - 23.02.1947?

Here is an example code snippet that can simulate the issue:

    int year = 1947;
    int month = 2;
    int day = 23;
    int timezoneOffset = TimeZone.getDefault().getRawOffset();
    Calendar calendar = Calendar.getInstance();
    calendar.clear();
    calendar.set(1, year);
    calendar.set(2, month - 1);
    calendar.set(5, day);
    calendar.set(15, timezoneOffset);

    System.out.println(calendar.getTime());

In my timezone the result of timezoneOffset is 3600000 in case you want to test my timezone (Czech Republic).

As a note this is a code written in WSO2, i am unable to change it in case there are questions about that.

Version of Java i am using for this is: openjdk 11.0.8 2020-07-14

Link: WSO2 platform

like image 351
Marcel Ouška Avatar asked Mar 24 '21 07:03

Marcel Ouška


People also ask

What does calendar getInstance() return?

Calendar 's getInstance method returns a Calendar object whose calendar fields have been initialized with the current date and time: Calendar rightNow = Calendar.

What is the use of calendar getInstance () in Java?

The getInstance() method in Calendar class is used to get a calendar using the current time zone and locale of the system. Parameters: The method does not take any parameters. Return Value: The method returns the calendar.

What is calendar in java?

Calendar class in Java is an abstract class that provides methods for converting date between a specific instant in time and a set of calendar fields such as MONTH, YEAR, HOUR, etc. It inherits Object class and implements the Comparable, Serializable, Cloneable interfaces.


2 Answers

On February 23 1947 the Czech Republic (Czechoslovakia, at the time) passed from the GMT timezone to the CET one, so clocks went 1 hour ahead. The opposite happened on December 1 1946 (CET->GMT, -1 hour).

This happened because the local government at the time implemented Winter Time, for the same reason we usually have DST, that is to (supposedly) save on energy consumption.

Link: Time Changes in Prague Over the Years on timeanddate.com

like image 168
Federico klez Culloca Avatar answered Nov 08 '22 05:11

Federico klez Culloca


The Answer by Federico klez Culloca is correct, and historically interesting.

In addition to that, I’ll point out that you are using terrible date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310. We can use java.time to see the change in offset explained in that other Answer.

Table of date-time types in Java, both modern and legacy

Here is a rewrite of your code to avoid those legacy classes.

First, establish the date.

int year = 1947;
int month = 2;
int day = 23;
LocalDate localDate = LocalDate.of(year,month,day);

Next, pick a couple of time-of-day values. 1 AM is before the 2 AM jump to 3 AM, and 4 AM is after the jump. Let's look at both.

LocalTime beforeJump = LocalTime.of( 1 , 0 ) ;
LocalTime afterJump = LocalTime.of( 4 , 0 ) ;

Define the time zone as a ZoneId.

ZoneId zoneId = ZoneId.of( "Europe/Prague" ) ;

Combine to determine a moment, getting a ZonedDateTime object.

ZonedDateTime zdtBeforeJump = ZonedDateTime.of( localDate , beforeJump , z );
ZonedDateTime zdtAfterJump = ZonedDateTime.of( localDate , afterJump , z );

When run:

zdtBeforeJump.toString() = 1947-02-23T01:00Z[Europe/Prague]
zdtAfterJump.toString() = 1947-02-23T04:00+01:00[Europe/Prague]

We can see in that generated text that the offset-from-UTC changed from zero hours-minutes-seconds as indicated by the Z (Zulu time) to an offset of 1 hour ahead of UTC.

We can interrogate for the offsets by code. From the ZoneId object, obtain the zone rules as a ZoneRules object. This provides a history of the past, present, and future changes to the offset used by the people of this particular region.

Adjust from our time zones to an offset of zero, producing the Instant object required by ZoneRules#getOffset. Then ask the rules for the exact offset-from-UTC in effect at that moment in that zone. We get a ZoneOffset object as a result.

ZoneRules rules = z.getRules();
ZoneOffset offsetBeforeJump = rules.getOffset( zdtBeforeJump.toInstant() );
ZoneOffset offsetAfterJump = rules.getOffset( zdtAfterJump.toInstant() );

When run.

offsetBeforeJump.toString() = Z
offsetAfterJump.toString() = +01:00

You can see all that code together run live at IdeOne.com.

➥ Same results as we saw with the generated text: Zero offset before the jump, and +01:00 after the jump.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
    • Java 9 brought some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android (26+) bundle implementations of the java.time classes.
    • For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
      • If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
like image 3
Basil Bourque Avatar answered Nov 08 '22 07:11

Basil Bourque