java.time
The java.util
Date-Time API and their formatting API, SimpleDateFormat
are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Note that a Date-Time without a timezone represents a local Date-Time which may be different for a different timezone e.g. today, it is 31st May 2021 in my timezone, Europe/London
whereas 1st June 2021 in Australia/Sydney
. So, in order to represent a moment (i.e. an instantaneous point on the timeline in UTC), Java provides a class called Instant
which you can convert to other Date-Time types e.g.
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
LocalDate todayUK = now.atZone(ZoneId.of("Europe/London")).toLocalDate();
LocalDate todaySydney = now.atZone(ZoneId.of("Australia/Sydney")).toLocalDate();
System.out.println(todayUK);
System.out.println(todaySydney);
LocalDateTime nowUK = now.atZone(ZoneId.of("Europe/London")).toLocalDateTime();
LocalDateTime nowSydney = now.atZone(ZoneId.of("Australia/Sydney")).toLocalDateTime();
System.out.println(nowUK);
System.out.println(nowSydney);
}
}
Output:
2021-05-31
2021-06-01
2021-05-31T16:22:40.418214
2021-06-01T01:22:40.418214
So, you need to choose a timezone. Most digital operations are based on the UTC (timezone offset, +00:00
hours).
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("d MMMM u", Locale.ENGLISH);
LocalDate date = LocalDate.parse("25 November 2010", dtf);
ZonedDateTime zdt = date.atStartOfDay(ZoneOffset.UTC);
Instant instant = zdt.toInstant();
System.out.println(instant);
long millis = instant.toEpochMilli();
System.out.println("Milliseconds since January 1, 1970, 00:00:00 GMT: " + millis);
}
}
Output:
2010-11-25T00:00:00Z
Milliseconds since January 1, 1970, 00:00:00 GMT: 1290643200000
The Z
in the sample output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC
timezone (which has the timezone offset of +00:00
hours).
Now, pass millis
to your insertEventtoCalendar
:
insertEventtoCalendar(millis);
Note: For any reason you need an object of java.util.Date
, you can get it from this Instant
as
Date date = Date.from(instant);
Learn more about java.time
, the modern Date-Time API* from Trail: Date Time.
What went wrong with your code?
You tried parsing the date string without setting a timezone and therefore, SimpleDateFormat
used your JVM's timezone to parse the date string, giving you a moment/instant corresponding to the start-of-the-day on 25 November 2010 in your timezone. To fix the problem, set the desired Timezone
(e.g. UTC) to the SimpleDateFormat
instance before parsing i.e.
SimpleDateFormat curFormater = new SimpleDateFormat("dd MMMM yyyy", Locale.ENGLISH);
curFormater.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
Two more important notes:
- Use
MMMM
instead of MMM
for the full monthname.
- Never use SimpleDateFormat or DateTimeFormatter without a Locale.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.