Initialize java.util.Calendar
with May, 31 1900
. Then add one year to it twenty times.
Here's code:
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
fun main(args : Array<String>) {
val f = SimpleDateFormat("yyyy.dd.MM")
val cal = Calendar.getInstance()
cal.set(1900, Calendar.MAY, 31)
for(i in 1..20) {
println(f.format(cal.time))
cal.add(Calendar.YEAR, 1)
}
}
The output is following:
1900.31.05
1901.31.05
1902.31.05
1903.31.05
1904.31.05
1905.31.05
1906.31.05
1907.31.05
1908.31.05
1909.31.05
1910.31.05
1911.31.05
1912.31.05
1913.31.05
1914.31.05
1915.31.05
1916.31.05
1917.31.05
1918.01.06
1919.01.06
Why I get June, 1 instead of May, 31 since 1918?
UPD: with time information
1917.31.05 23:38:50.611
1918.01.06 01:38:50.611
If this is DST invention, how do I prevent that?
You seem to be running your code in a timezone that changed its offset by two hours in 1917 or 1918. That is, the number of hours ahead or behind UTC changed. I've no idea why your timezone would have done that, but I'm sure there's a good historical reason for it.
If you're only interested in dates, without the Time component, use the java.time.LocalDate
class, which effectively represents a day, month and year only. It's not subject to any daylight savings anomalies.
LocalDate today = LocalDate.now();
or
LocalDate moonLanding = LocalDate.of(1969, 7, 20);
I am assuming that you are in Europe/Moscow time zone. Turing85 in a comment correctly spotted the cause of the behaviour you observed: In 1918 summer time (DST) in your time zone began on May 31. The clock was moved forward from 22:00 to 24:00, that is, by two hours. Your Calendar
object is aware of this and therefore refuses to give 23:38:50.611 on this date. Instead it picks the time 2 hours later, 1918.01.06 01:38:50.611. Now the month and day-of-month have changed to 1st of June.
Unfortunately this change is kept in the Calendar
and carried on to the following year.
If this is DST invention, how do I prevent that?
Thomas Kläger in a comment gave the right solution: If you only need the dates, use LocalDate
from java.time
:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu.dd.MM");
LocalDate date = LocalDate.of(1900, Month.MAY, 31);
for (int i = 1; i <= 20; i++) {
System.out.println(date.format(dateFormatter));
date = date.plusYears(1);
}
Output (abbreviated):
1900.31.05
1901.31.05
…
1917.31.05
1918.31.05
1919.31.05
The “local” in LocalDate
means “without timezone” in java.time
jargon, so this is guaranteed to keep you free of surprises from time zone anomalies.
If you need a time, you may consider LocalDateTime
, but since this is without time zone too, it will give you the non-existing time of 1918.31.05 23:38:50.611, so maybe not.
An alternative thing you may consider is adding the right number of years to your origin of 1900.31.05 23:38:50.611. Then at least you will only have surprises in years where you hit a non-existing time. I am using ZonedDateTime
for this demonstration:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu.dd.MM HH:mm:ss.SSS");
ZonedDateTime originalDateTime = ZonedDateTime.of(1900, Month.MAY.getValue(), 31,
23, 30, 50, 611000000, ZoneId.of("Europe/Moscow"));
for (int i = 0; i < 25; i++) {
System.out.println(originalDateTime.plusYears(i).format(formatter));
}
Output:
1900.31.05 23:30:50.611
1901.31.05 23:30:50.611
…
1917.31.05 23:30:50.611
1918.01.06 01:30:50.611
1919.01.06 00:30:50.611
1920.31.05 23:30:50.611
…
1924.31.05 23:30:50.611
Again in 1919 summer time began on May 31. This time the clock was only advanced by 1 hour, from 23 to 24, so you get only 1 hour later than the imaginary time of 23:30:50.611.
I am recommending java.time
for date and time work, not least when doing math on dates like you do. The Calendar
class is considered long outmoded. java.time
was designed acknowledging that Calendar
and the other old classes were poorly designed. The modern ones are so much nicer to work with.
In no other time zone than Europe/Moscow is the time of 1918.31.05 23:38:50.611 nonexistent. I checked:
LocalDateTime dateTime = LocalDateTime.of(1918, Month.MAY, 31, 23, 38, 50, 611000000);
for (String zid : ZoneId.getAvailableZoneIds()) {
ZonedDateTime zdt = dateTime.atZone(ZoneId.of(zid));
LocalDateTime newDateTime = zdt.toLocalDateTime();
if (! newDateTime.equals(dateTime)) {
System.out.println(zid + ": -> " + zdt + " -> " + newDateTime);
}
}
Output:
Europe/Moscow: -> 1918-06-01T01:38:50.611+04:31:19[Europe/Moscow] -> 1918-06-01T01:38:50.611
W-SU: -> 1918-06-01T01:38:50.611+04:31:19[W-SU] -> 1918-06-01T01:38:50.611
“W-SU” is a deprecated name for the same time zone, it stands for Western Soviet Union.
java.time
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With