How do i convert ZonedDateTime to java.util.Date without changing the timezone.
In my below method when i call Date.from(datetime.toInstant()) it convert it to local time zone in my case SGT.
public static void printDate(ZonedDateTime datetime) {
System.out.println("---> " + datetime.format(DateTimeFormatter.ofPattern(API_TIME_STAMP_PATTERN)));
System.out.println(Date.from(datetime.toInstant()));
System.out.println("\n");
}
Output
---> 2019-03-13_08:46:26.593
Wed Mar 13 16:46:26 SGT 2019
You can add offset millis by yourself. See the example using java.util.Date:
long offsetMillis = ZoneOffset.from(dateTime).getTotalSeconds() * 1000;
long isoMillis = dateTime.toInstant().toEpochMilli();
Date date = new Date(isoMillis + offsetMillis);
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*. However, for any reason, if you want to change java.time.ZonedDateTime to java.util.Date, I recommend you avoid any kind of manual calculations when you already have an inbuilt API to meet the requirement.
All you need to do is to add the offset to the input datetime which you can do by using ZonedDateTime#plusSeconds as shown below:
datetime = datetime.plusSeconds(datetime.getOffset().getTotalSeconds());
Date date = Date.from(datetime.toInstant());
Demo:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
// Test
printDate(ZonedDateTime.now(ZoneId.of("Asia/Singapore")));
}
public static void printDate(ZonedDateTime datetime) {
datetime = datetime.plusSeconds(datetime.getOffset().getTotalSeconds());
Date date = Date.from(datetime.toInstant());
// Showing date-time in Singapore timezone
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Singapore"));
System.out.println(sdf.format(date));
}
}
Output:
2021-10-03T05:11:57
ONLINE DEMO
Learn more about the modern Date-Time API* from Trail: Date Time.
* 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.
I would do as ETO states on his answer with the exception of using TimeUnit for getting the seconds converted into milliseconds:
long offsetMillis = TimeUnit.SECONDS.toMillis(ZoneOffset.from(dateTime).getTotalSeconds());
long isoMillis = dateTime.toInstant().toEpochMilli();
Date date = new Date(isoMillis + offsetMillis);
or the other option would be:
var localDate = LocalDateTime.now();
final long offSetHours = ChronoUnit.HOURS.between(localDate.atZone(ZoneId.of("YOUR_TIME_ZONE_ID")),
localDate.atZone(ZoneId.of("UTC")));
return Date.from(Instant.parse(dateAsStringISO8601).plus(offSetHours, ChronoUnit.HOURS));
Stick to ZonedDateTime
To preserve the time zone simply preserve your ZonedDateTime. It can be formatted directly to the output your require. Don’t involve the outdated and poorly designed Date class.
private static final String API_TIME_STAMP_PATTERN = "yyyy-MM-dd_HH:mm:ss.SSS";
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz y", Locale.ROOT);
public static void printDate(ZonedDateTime datetime) {
System.out.println("---> " + datetime.format(DateTimeFormatter.ofPattern(API_TIME_STAMP_PATTERN)));
System.out.println(datetime.format(FORMATTER));
System.out.println("\n");
}
Try it out:
ZonedDateTime zdt = ZonedDateTime.of(
2019, 3, 13, 8, 46, 26, 593_000_000, ZoneId.of("Etc/UTC"));
printDate(zdt);
Output:
---> 2019-03-13_08:46:26.593
Wed Mar 13 08:46:26 UTC 2019
Your conversion is not changing the time zone
A Date falsely pretends to have a time zone. It hasn’t got any. So there is no change of time zone going on. toInstant() discards the time zone because an Instant hasn’t got a time zone either. Date.from() performs the conversion withut any regard to time zone. System.out.println() implicitly calls Date.toString(). The toString() method uses the JVM’s default time zone for rendering the string. It’s pretty confusing alright.
Related
I have a logic in python that I am converting into Java code.
The logic is I need to read from a timestamp attribute in JSON file and convert it into ISO date format.
Python query:
datetime.datetime.fromtimestamp(jsonMsg["time"]).isoformat(timespec='seconds')
Here is the code I wrote in Java
1627065646.444 is an example of the value I get from JSON script
long timestamp = (long) 1627065646.444 * 1000;
Timestamp time = new Timestamp(timestamp);
Date d = new Date(time.getTime());
DateFormat df = new SimpleDateFormat();
String dateToString = df.format(d);
LocalDateTime datetime = LocalDateTime.parse(dateToString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
ZoneOffset offset = ZoneOffset.UTC;
String formattedTimeStamp = datetime.atOffset(offset).toString();
When I run the code I get compile error "Text '7/23/21 11:40 AM' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0"
This exception occurs at LocalDateTime.parse(dateToString, DateTimeFormatter.ISO_LOCAL_DATE_TIME. Can someone please help me in understanding what I am doing wrong here.
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*.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
import java.time.LocalDateTime;
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) {
long timestamp = (long) (1627065646.444 * 1000);
Instant instant = Instant.ofEpochMilli(timestamp);
System.out.println(instant);
ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC);
LocalDateTime ldt = zdt.toLocalDateTime();
System.out.println(ldt);
// A custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u h:m:s a", Locale.ENGLISH);
String formatted = dtf.format(zdt);
System.out.println(formatted);
}
}
Output:
2021-07-23T18:40:46.444Z
2021-07-23T18:40:46.444
7/23/2021 6:40:46 PM
ONLINE DEMO
The Z in the output is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).
Learn more about the modern Date-Time API* from Trail: Date Time.
Apart from this, what else is wrong with your code?
You have done
long timestamp = (long) 1627065646.444 * 1000;
in which 1627065646.444 will be cast to long resulting in 1627065646 and thus the result of the multiplication will be 1627065646000, not 1627065646444 what you are expecting. You need to cast to long after performing the multiplication.
A valuable comment by Ole V.V.:
I’d use Math.round(1627065646.444 * 1000) to make sure that
floating-point inaccuracy is handled.
* 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.
There is an XMLGregorianCalendar object that contains the value "2021-01-18T18:43:26.884Z" (This is its output in toString()). When I try to serialize this date with Jackson, I get a date 3 hours later in the output:
XMLGregorianCalendar date = ...;
ObjectMapper mapper = new ObjectMapper();
String out = mapper.writeValueAsString(obj); // Output: 1610995406884 (Converted to Date: Mon Jan 18 21:43:26 MSK 2021)
How can I solve this problem?
There is no problem at all.
The time "2021-01-18T18:43:26.884Z" in your XMLGregorianCalendar
is 18:43 in the GMT timezone (Greenwich mean time, London) or UTC+0 (because of the trailing Z).
In the other hand you have a Date object with the string representation
"Mon Jan 18 21:43:26 MSK 2021",
which is 21:43 in the MSK timezone (Moscow Standard Time) or UTC+3.
The Date class chose this timezone for formatting the output
simply because your computer is located near Moscow.
So both are actually the same point in time,
just only stringified for two different timezones.
java.util.Date represents the number of milliseconds since the epoch
The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(1610995406884L);
Date date = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date));
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println(sdf.format(date));
}
}
Output:
2021-01-18T18:43:26.884
2021-01-18T21:43:26.884
Note that the date-time API of java.util 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.
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.
Convert the legacy, java.util.Date to the modern java.time.Instant using java.util.Date#toInstant:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(1610995406884L);
Date date = calendar.getTime();
Instant instant = date.toInstant();
System.out.println(instant);
// You can convert Instant to other types e.g.
ZonedDateTime zdt = instant.atZone(ZoneId.of("Europe/Moscow"));
// Print default format i.e. the value of zdt#toString
System.out.println(zdt);
// Custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss'['z']'");
String formatted = dtf.format(zdt);
System.out.println(formatted);
}
}
Output:
2021-01-18T18:43:26.884Z
2021-01-18T21:43:26.884+03:00[Europe/Moscow]
2021-01-18T21:43:26[MSK]
The Z stands for Zulu and represents UTC (or GMT).
I currently have a Date e.g. "2015-10-10T14:34:22Z". I need the year from the Date object for my new LocalDateTime object as this object will be set to that Date object year and have a specific month, day and time set (yyyy-06-15T17:00:00Z).
Taking the getYear() from Date has the 1900 issue.
I get the date via LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
Create another object to set the desired month and day
Create LocalDateTime object to set the time
I feel I am doing it a very long convuluted way and would like to ask if there are any other shorter and better alternatives.
EDIT:
Are there are any other shorter and better alternatives?
Since your date-time string has timezone offset information. So, you can parse it to an OffsetDateTime object and then get the year from it.
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
String strDateTime = "2015-10-10T14:34:22Z";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt);
System.out.println(odt.getYear());
// If you want to get LocalDateTime from OffsetDateTime
LocalDateTime ldt = odt.toLocalDateTime();
System.out.println(ldt);
}
}
Output:
2015-10-10T14:34:22Z
2015
2015-10-10T14:34:22
Note that Z in the date-time string stands for Zulu date-time and specifies a timezone offset of +00:00 hours or date-time at UTC.
Taking the getYear() from Date has the 1900 issue.
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. I suggest you should stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.
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.
Converting from legacy API to the modern API:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Date;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "2015-10-10T14:34:22Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
Date date = sdf.parse(strDateTime);
Instant instant = date.toInstant();
OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);
System.out.println(odt);
System.out.println(odt.getYear());
// If you want to get LocalDateTime from OffsetDateTime
LocalDateTime ldt = odt.toLocalDateTime();
System.out.println(ldt);
}
}
Output:
2015-10-10T14:34:22Z
2015
2015-10-10T14:34:22
Note: If you want to convert the Instant into ZonedDateTime at UTC, you can do it as follows:
ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC);
or the following:
ZonedDateTime zdt = instant.atZone(ZoneId.of("Etc/UTC"));
Note that the three-letter name for a ZoneId is error-prone i.e. avoid using something like ZoneId.of("UTC").
What is wrong with your code:
You are using .atZone(ZoneId.systemDefault()) which is converting the object of Instant to an object of ZonedDateTime with your JVM's timezone. You have to use .atOffset(ZoneOffset.UTC) as shown above to keep the date-time with the same timezone offset (i.e. +00:00 hours or date-time at UTC) which is there in the date-time string.
try this :
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssX");
try {
String s = "2015-10-10T14:34:22+02";
s = s.replaceAll("T", " ");
Date d = df.parse(s);
Calendar cl = Calendar.getInstance();
cl.setTime(d);
System.out.println(cl.getTime());
System.out.println("year : " + cl.get(Calendar.YEAR));
} catch (ParseException e) {
System.err.println(e);
}
output
Sat Oct 10 13:34:22 GMT+01:00 2015
year : 2015
Maybe this approach could help:
import java.text.ParseException;
import java.time.*;
import java.util.Date;
public class ConvertDate {
public static void main(String[] args) throws ParseException {
Date date = new Date();
LocalDateTime localDateTime = date.toInstant().atOffset(ZoneOffset.UTC).toLocalDateTime();
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());
}
}
Time zone is crucial
You need to decide in which time zone you want the year. New Year doesn’t happen at one point in time across the globe, but over a span of about 26 hours. So if your date string is within a day or so of New Year, your result could be off by a year if you don’t pick the correct time zone. For example:
ZoneId zone = ZoneId.of("America/Louisville");
// The year in the following object does not matter
ZonedDateTime fixedTimeOfYear = ZonedDateTime.of(2020, 6, 15, 17, 0, 0, 0, zone);
String inputString = "2015-01-01T01:02:03Z";
OffsetDateTime input = OffsetDateTime.parse(inputString);
int year = input.atZoneSameInstant(zone).getYear();
System.out.format("Year in %s is %d%n", zone, year);
ZonedDateTime desiredTime = fixedTimeOfYear.withYear(year);
System.out.println("Result: " + desiredTime);
Output from this snippet is:
Year in America/Louisville is 2014
Result: 2014-06-15T17:00-04:00[America/Louisville]
You notice that even though the year in the string is 2015, it is still only 2014 in the time zone that I chose for the demonstration, so the resulting date and time are in 2014. The example was picked to demonstrate my point.
Don’t use LocalDateTime
The frequent use of LocalDateTime that you mention in a comment is a misunderstanding. For a date and time in a known time zone in 2015, for example, LocalDateTime is the wrong class to use. Use ZonedDateTime or at least OffsetDateTime so we know what we are talking about. These classes have the advantages that they keep track of time zone or offset themselves, and that they define an unambiguous point in time. LocalDateTime does nothing of this.
Here is my simple code:
String defaultSimpleDateFormatPattern = "MMM dd, yyyy HH:mm:ss";
TimeZone tzNY = TimeZone.getTimeZone("America/New_York");
TimeZone tzLos = TimeZone.getTimeZone("America/Los_Angeles");
String dateToTest = "Jan 03, 2015 23:59:59";
SimpleDateFormat df = new SimpleDateFormat(defaultSimpleDateFormatPattern);
Calendar c = Calendar.getInstance();
c.setTime(df.parse(dateToTest));
c.setTimeZone(tzLos);
System.out.println(c.getTimeZone());
System.out.println(c.getTime());
System.out.println(df.format(c.getTime()));
Calendar c1 = Calendar.getInstance();
c1.setTime(df.parse(dateToTest));
c1.setTimeZone(tzNY);
System.out.println(c1.getTimeZone());
System.out.println(c1.getTime());
System.out.println(df.format(c1.getTime()));
System.out.println(c.after(c1)? "after" : (c.before(c1)? "before" : "equal"));
The printout is "equal". How is that? any explanation on this result?
There are two problems here:
You're using an invalid time zone ID (you want America/New_York)
You're parsing using a formatter that hasn't got a time zone set (so it'll use the default time zone) and then setting the time zone in the Calendar afterwards... that doesn't change the instant in time being represented
So basically you're parsing to the same Date twice, doing things which don't affect the Date being represented, and then comparing the two equal Date values.
If at all possible, you should use Joda Time or java.time instead of java.util.Calendar, but if you really need to use it, just create two different formatters, one with each time zone. (You'll need to set the time zone in the Calendar as well, if you actually need the Calendar...)
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*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API: Your Date-Time string does not have timezone information and therefore it can be described as a local Date-Time. So, parse it to LocalDateTime and apply the timezone to it to get the ZonedDateTime.
Demo:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String defaultSimpleDateFormatPattern = "MMM dd, uuuu HH:mm:ss";
ZoneId tzNY = ZoneId.of("America/New_York");
ZoneId tzLos = ZoneId.of("America/Los_Angeles");
String dateToTest = "Jan 03, 2015 23:59:59";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(defaultSimpleDateFormatPattern, Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(dateToTest, dtf);
ZonedDateTime zdtNY = ldt.atZone(tzNY);
ZonedDateTime zdtLos = ldt.atZone(tzLos);
System.out.println(zdtNY.isAfter(zdtLos) ? "after" : zdtNY.isBefore(zdtLos) ? "before" : "equal");
}
}
Output:
before
ONLINE DEMO
Alternatively, Create separate DateTimeFormatter specific to each timezone i.e. ask Java to parse the local Date-Time string applying the given timezone.
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String defaultSimpleDateFormatPattern = "MMM dd, uuuu HH:mm:ss";
ZoneId tzNY = ZoneId.of("America/New_York");
ZoneId tzLos = ZoneId.of("America/Los_Angeles");
String dateToTest = "Jan 03, 2015 23:59:59";
DateTimeFormatter dtfNY = DateTimeFormatter.ofPattern(defaultSimpleDateFormatPattern, Locale.ENGLISH)
.withZone(tzNY);
DateTimeFormatter dtfLos = DateTimeFormatter.ofPattern(defaultSimpleDateFormatPattern, Locale.ENGLISH)
.withZone(tzLos);
ZonedDateTime zdtNY = ZonedDateTime.parse(dateToTest, dtfNY);
ZonedDateTime zdtLos = ZonedDateTime.parse(dateToTest, dtfLos);
System.out.println(zdtNY.isAfter(zdtLos) ? "after" : zdtNY.isBefore(zdtLos) ? "before" : "equal");
}
}
Output:
before
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
What is wrong with your code?
You have not set a timezone to your SimpleDateFormat: Unlike the modern Date-Time API with which you have multiple ways to create a Date-Time object specific to a timezone, you have only this way with the legacy API to deal with such a situation (because java.util.Date does not hold timezone information). It is similar to the alternative example shown above.
You have not set a Locale to your SimpleDateFormat: Never use SimpleDateFormat or DateTimeFormatter without a Locale. Luckily, your program did not crash because your JVM's timezone must be an English locale.
Demo:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String defaultSimpleDateFormatPattern = "MMM dd, yyyy HH:mm:ss";
TimeZone tzNY = TimeZone.getTimeZone("America/New_York");
TimeZone tzLos = TimeZone.getTimeZone("America/Los_Angeles");
String dateToTest = "Jan 03, 2015 23:59:59";
SimpleDateFormat df = new SimpleDateFormat(defaultSimpleDateFormatPattern, Locale.ENGLISH);
df.setTimeZone(tzNY);
Calendar c = Calendar.getInstance();
c.setTime(df.parse(dateToTest));
df.setTimeZone(tzLos);
Calendar c1 = Calendar.getInstance(tzNY);
c1.setTime(df.parse(dateToTest));
System.out.println(c.after(c1) ? "after" : (c.before(c1) ? "before" : "equal"));
}
}
Output:
before
ONLINE DEMO
* 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.
I have a date in string format as 25 November 2010 and I am trying to fetch the milliseconds of that date, for that I have written the below code:
strDateSelcted = "25 November 2010" // Actually I am receiving date in this format
SimpleDateFormat curFormater = new SimpleDateFormat("dd MMM yyyy");
try {
Date dateObj = curFormater.parse(strDateSelcted);
insertEventtoCalendar(dateObj.getTime()); // Actually insert an event onto the native calendar
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
But, when I try to run the application,it creates an event a day before the date inserted, i.e. For 25 November 2010 it inserts event on 24 November 2010 and For 27 November 2010 it inserts event on 26 November 2010, and same.
Where am I making a mistake?
To set the timezone used by the date formatter: call the setTimeZone method
e.g.
curFormater.setTimeZone(TimeZone.getTimeZone("UTC"));
For one, your date pattern is wrong, use dd MMMM yyyy. MMM parses & returns Nov (not November).
Also, since there is no millisecond provided in your date string, the millisecond will be set to 0.
Seeing that Jon Skeet updated me with the question, it might be timezone issue (as he mentioned). Sorry for the misunderstanding.
Test code:
/**
*
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* #author The Elite Gentleman
*
*/
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
String date = "25 November 2010";
SimpleDateFormat sdf = new SimpleDateFormat("dd MMMM yyyy");
Date d = sdf.parse(date);
System.out.println(d.getTime());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Value: 1290636000000
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.
It's almost certainly a time zone issue. Check which time zone your SimpleDateFormat is using, and the one your phone is using to display the event.
For diagnostic purposes I suggest you log the result of dateObj.getTime() and you can check exactly what that means on a desktop machine.
Use Locale.getDefault() when Your using SimpleDateFormat.I hope it may solve your problem.