Joda Time toDate() wrong result - java

I am using this code:
date - Date object from DatePicker, as string Thu Sep 10 00:00:00 GMT+03:00 2020
mDate = DateTime(date)
.withHourOfDay(0)
.withMinuteOfHour(0)
.withSecondOfMinute(0)
.withMillisOfSecond(0)
.toDate()
The result
mDate - Wed Sep 09 03:00:00 GMT+03:00 2020
What wrong with this?

You are not converting the DateTime object to java.util.Date correctly. A correct way is to get the milliseconds from DateTime object and initialize the java.util.Date with the milliseconds.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// Define formatter
DateTimeFormatter formatter = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss zZ yyyy");
// Date-time string from DatePicker
String strDateTime = "Thu Sep 10 00:00:00 GMT+03:00 2020";
DateTime dateTime = DateTime.parse(strDateTime, formatter);
System.out.println(dateTime);
// No. of milliseconds from the epoch of 1970-01-01T00:00:00Z
long millis = dateTime.getMillis();
System.out.println(millis);
Date mDate = new Date(millis);
// Display java.util.Date object in my default time-zone (BST)
System.out.println(mDate);
//Display java.util.Date in a different time-zone and using custom format
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("GMT+3"));
System.out.println(sdf.format(mDate));
}
}
Output:
2020-09-09T21:00:00.000Z
1599685200000
Wed Sep 09 22:00:00 BST 2020
Thu Sep 10 00:00:00 GMT+03:00 2020
Note: java.util.Date does not represent a Date/Time object. It simply represents the no. of milliseconds from the epoch of 1970-01-01T00:00:00Z. It does not have any time-zone or zone-offset information. When you print it, Java prints the string obtained by applying the time-zone of your JVM. If you want to print it in some other timezone, you can do so using the SimpleDateFormat as shown above.
I recommend you switch from the outdated and error-prone java.util date-time API and SimpleDateFormat to the modern java.time date-time API and the corresponding formatting API (package, java.time.format). Learn more about the modern date-time API from Trail: Date Time. If your Android API level is still not compliant with Java8, check How to use ThreeTenABP in Android Project and Java 8+ APIs available through desugaring.
The following table shows an overview of modern date-time classes:

Related

Date is displaying in different time zone when parsing a string using SimpleDateFormat [duplicate]

This question already has answers here:
Java date parsing has stranger behavior where parsing different date in different timezone
(1 answer)
Java Date timezone printing different timezones for different years, Workaround needed
(4 answers)
Closed 3 months ago.
public class ParseDate {
public static final String DATE_FORMAT = "yyyy-MM-dd";
public static SimpleDateFormat DateFormatter = new SimpleDateFormat(DATE_FORMAT);
public static void main(String[] args) {
try {
System.out.println("Converting 2020-12-31 to "+DateFormatter.parse("2020-12-31"));
System.out.println("Converting 2020-06-30 to "+DateFormatter.parse("2020-06-30"));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Output:
Converting 2020-12-31 to Thu Dec 31 00:00:00 GMT 2020
Converting 2020-06-30 to Tue Jun 30 00:00:00 BST 2020
If I execute this code, I am getting different time zones (GMT and BST) as output.
How to get same time zone of Date object as output irrespective of different input strings.
When I was executed the code, I expect the date object should contain same time zone (either GMT or BST).
I have tried with the below time zone:
java.util.Date is not a true date-time object; rather, it just represents the number of milliseconds from January 1, 1970, 00:00:00 GMT. The Date#toString returns this millisecond value into a string applying the default timezone which is Europe/London in your case and therefore it prints GMT and BST because of DST.
java.time
The java.time API, released with Java-8 in March 2014, supplanted the error-prone legacy date-time API. Since then, using this modern date-time API has been strongly recommended.
Demo using modern date-time API
import java.time.LocalDate;
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) {
ZoneId zoneId = ZoneId.of("Europe/London");
ZonedDateTime zdt1 = LocalDate.parse("2020-12-31").atStartOfDay(zoneId);
ZonedDateTime zdt2 = LocalDate.parse("2020-06-30").atStartOfDay(zoneId);
System.out.println("Converting 2020-12-31 to " + zdt1);
System.out.println("Converting 2020-06-30 to " + zdt2);
// Date#toString like format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
System.out.println(zdt1.format(formatter));
System.out.println(zdt2.format(formatter));
}
}
Output:
Converting 2020-12-31 to 2020-12-31T00:00Z[Europe/London]
Converting 2020-06-30 to 2020-06-30T00:00+01:00[Europe/London]
Thu Dec 31 00:00:00 GMT 2020
Tue Jun 30 00:00:00 BST 2020
Note that since java.time API is based on ISO 8601 standard, you do not need to specify a parser ( DateTimeFormatter in the case of java.time API) to parse a date string which is already in this format.
Learn more about the modern Date-Time API from Trail: Date Time.

Need Calendar Instance only date (not time) and compare with date String in Kotlin as it lags

I need only date from Calendar Instance not the time. Whenever i used calendar object it returns the date with time.
val calendar = Calendar.getInstance()
calendar.time. // Mon Nov 09 11:41:29 GMT 2020
I change this by using SimpleDateFormat
SimpleDateFormat("dd/MM/yyyy").format(date)
09/09/2020
I am creating calendar so i have huge amount of data in list. I am adding data at specific date. So I am comparing dates with string date. My string date Format is look like this :-
20/05/2020
So there is too much performance issue like lagging the view. So is there any thing which i can use to avoid all this thing.
val calendarModel = dataList?.find {
SimpleDateFormat("dd/MM/yyyy").format(it.date) == item
}
Calendar#getTime returns a java.util.Date object representing this Calendar's time value which is a millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT.
Thus, java.util.Date does not represent a real date or time or date-time object. When you print this millisecond value, your JVM calculates the date and time in its time-zone and when you print its object, you get what java.util.Date#toString returns. From this explanation, you must have already understood that this millisecond value will be the same irrespective of the timezone as it is not a timezone based value; rather, it is fakely represented by java.util.Date#toString as a timezone based value. Just to demonstrate what I have just said, look at the output of the following program:
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
Date date = new Date();
System.out.println("Asia/Calcutta:");
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Calcutta"));
System.out.println(date.getTime());
System.out.println(date);
System.out.println("\nEurope/London:");
TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
System.out.println(date.getTime());
System.out.println(date);
System.out.println("\nAfrica/Johannesburg:");
TimeZone.setDefault(TimeZone.getTimeZone("Africa/Johannesburg"));
System.out.println(date.getTime());
System.out.println(date);
System.out.println("\nAmerica/New_York:");
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
System.out.println(date.getTime());
System.out.println(date);
}
}
Output:
Asia/Calcutta:
1604747702688
Sat Nov 07 16:45:02 IST 2020
Europe/London:
1604747702688
Sat Nov 07 11:15:02 GMT 2020
Africa/Johannesburg:
1604747702688
Sat Nov 07 13:15:02 SAST 2020
America/New_York:
1604747702688
Sat Nov 07 06:15:02 EST 2020
The modern date-time API has real date-time classes. Given below is an overview of these classes:
As you can find in this table, there is a class, LocalDate which represents just date (consisting of a year, month, and day). Given below is a quick demo of the modern java.time API:
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
// A date with the given year, month and day-of-month
LocalDate date = LocalDate.of(2010, Month.NOVEMBER, 7);
System.out.println(date);
// Today (in the JVM's timezone)
LocalDate today = LocalDate.now(); // Same as LocalDate.now(ZoneId.systemDefault())
System.out.println(today);
// Today at UTC
LocalDate todayAtUTC = LocalDate.now(ZoneOffset.UTC);
System.out.println(todayAtUTC);
// Today in India
LocalDate todayInIndia = LocalDate.now(ZoneId.of("Asia/Calcutta"));
System.out.println(todayAtUTC);
}
}
Output:
2010-11-07
2020-11-07
2020-11-07
2020-11-07
Learn more about the modern date-time API at Trail: Date Time.
Recommendation: 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.
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.

how to parse the following date format Mon Nov 09 2015 00:00:00 GMT+0530 (India Standard Time) in java

I am getting the date in the format Mon Nov 09 2015 00:00:00 GMT+0530 (India Standard Time). I have to convert it to sql date of format dd/MM/yyyy. Please help.
I tried below code but did not help
Date date = new java.sql.Date(
(new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zz (zzzz)").parse("Mon Nov 09 2015 00:00:00 GMT+0530 (India Standard Time)"))
.getTime());
Something like below, also refer here for Java SimpleDateFormat
public static void main(String[] args) throws ParseException {
String time = "Mon Nov 09 2015 00:00:00 GMT+0530 (India Standard Time)";
DateFormat inputFormat = new SimpleDateFormat(
"E MMM dd yyyy HH:mm:ss 'GMT'z", Locale.ENGLISH);
Date date = inputFormat.parse(time);
System.out.println(date);
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy", Locale.US);
System.out.println(formatter.format(date));
}
output
Mon Nov 09 00:00:00 IST 2015
09/11/2015
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* .
Since your date-time string has timezone information, parse it into ZonedDateTime which you can convert to other java.time types and if required, format into the desired formats.
Demo:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "Mon Nov 09 2015 00:00:00 GMT+0530 (India Standard Time)";
DateTimeFormatter dtfInput = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("E MMM d uuuu H:m:s")
.appendLiteral(" ")
.appendZoneId()
.appendPattern("X")
.appendLiteral(" ")
.appendLiteral("(")
.appendGenericZoneText(TextStyle.FULL)
.appendLiteral(')')
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtfInput);
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(odt);
// To LocalDate, LocalDateTime etc.
LocalDate localDate = odt.toLocalDate();
LocalDateTime localDateTime = odt.toLocalDateTime();
System.out.println(localDate);
System.out.println(localDateTime);
// Get the formatted string
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("dd/MM/uuuu", Locale.ENGLISH);
String formatted = dtfOutput.format(localDate);
System.out.println(formatted);
// In UTC
odt = odt.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println(odt);
}
}
Output:
2015-11-09T00:00+05:30
2015-11-09
2015-11-09T00:00
09/11/2015
2015-11-08T18:30Z
Learn more about the modern date-time API from Trail: Date Time.
Support for OffsetDateTime in JDBC:
Starting with JDBC 4.2, you can use OffsetDateTime directly in your code e.g.
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);
st.executeUpdate();
st.close();
The support for java.time API in JDBC Java SE 8 (JDBC 4.2) came without requiring any public JDBC API changes. The setObject and getObject methods support java.time types as per the following mapping:
Note for PostgreSQLâ„¢: ZonedDateTime, Instant and OffsetTime / TIME WITH TIME ZONE are not supported. Also, the OffsetDateTime instances need to be in UTC (have offset 0).
* 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 dealt with something like this right now, and this is my solution:
String dateString = new SimpleDateFormat("dd/MM/yyyy").format(timestamp.toDate()).toString();

Input date Jan 03 but returns Jan 02, why?

public static void main(String[] args) {
String opDate = "Tue Jan 03 00:00:00 MSK 2006";
String date = convertDate(opDate, "yyyyMMdd");
System.out.println("opDate: " + opDate);
System.out.println("date: " + date);
}
public static String convertDate(String opDate, String dateFormat) {
Date date = new Date();
// Mon Jan 02 00:00:00 MSK 2006
SimpleDateFormat dateParser = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
try {
date = dateParser.parse(opDate);
} catch (Exception e) {
System.out.println("exception = " + e.toString());
}
SimpleDateFormat df = new SimpleDateFormat(dateFormat);
df.setTimeZone(TimeZone.getTimeZone("Russia/Moscow"));
String strDate = df.format( date.getTime() );
return strDate.trim();
}
out:
opDate: Tue Jan 03 00:00:00 MSK 2006
date: 20060102
Why does it return Jan 02?
The problem is the fetching of the "Russia/Moscow" time zone. The correct zoneinfo ID is "Europe/Moscow". Change the ID, and the problem goes away:
df.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
It's unfortunate that TimeZone.getTimeZone("random rubbish") returns the UTC time zone rather than letting you know in some way that it's broken.
Probably due to timezone conversion.
I would suggest you also print the time and the timezone of your resulting date. This is likely to be Jan 2, 23:00 or something.
This happens because you set a different timezone on the SimpleDataFormat.
Timezones.
You're specifying midnight on January 3rd in MSK. This is 9pm on the 2nd January in GMT (the likely default timezone).
I can see that you're trying to output in Moscow time as well, but Russia/Moscow is not a valid timezone, and the getTimeZone call "helpfully" silently defaults to returning GMT. This then of course doesn't change the time zone of the date when formatting and outputs it as 2 Jan.
If you set the timezone to Europe/Moscow, you'll get the expected output.
May it be related to the fact that you're converting dates between two distinct TimeZones?
If you change line:
String date = convertDate(opDate, "yyyyMMdd");
to:
String date = convertDate(opDate, "EEE MMM dd HH:mm:ss zzz yyyy");
you can see the output of your program:
opDate: Tue Jan 03 00:00:00 MSK 2006
date: Mon Jan 02 20:00:00 GMT 2006
You are not setting well TimeZone with:
df.setTimeZone(TimeZone.getTimeZone("Russia/Moscow"));
you need:
df.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
Finally there are summer delay of 1h.
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.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "Tue Jan 03 00:00:00 MSK 2006";
String formatted = formatDateTimeStringTo(strDateTime, "yyyyMMdd", Locale.ENGLISH);
System.out.println("opDate: " + strDateTime);
System.out.println("date: " + formatted);
}
public static String formatDateTimeStringTo(String strDateTime, String targetFormat, Locale locale) {
DateTimeFormatter parser = DateTimeFormatter.ofPattern("EEE MMM d H:m:s zzz u", locale);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(targetFormat, locale);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, parser);
// System.out.println(zdt); // 2006-01-03T00:00+03:00[Europe/Moscow]
return zdt.format(formatter);
}
}
Output:
opDate: Tue Jan 03 00:00:00 MSK 2006
date: 20060103
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
Follow the standard convention to name the timezone:
Ask your publisher to switch to the standard naming convention of the timezone. The standard naming convention is Region/City e.g. Europe/Moscow. The two/three/four letter abbreviation for the timezone is error-prone as described in the following text at the Timezone documentation page:
Three-letter time zone IDs
For compatibility with JDK 1.1.x, some other three-letter time zone
IDs (such as "PST", "CTT", "AST") are also supported. However, their
use is deprecated because the same abbreviation is often used for
multiple time zones (for example, "CST" could be U.S. "Central
Standard Time" and "China Standard Time"), and the Java platform can
then only recognize one of them.
* 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.

Java SimpleDateFormat Wrong Timezone after parsing

Why: When I give input date string with GMT timezone, SimpleDateFormat parses it and outputs EET timezone?
public static String DATE_FORMAT="dd MMM yyyy hh:mm:ss z";
public static String CURRENT_DATE_STRING ="31 October 2011 11:19:56 GMT";
...
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(simpleDateFormat.parseObject(CURRENT_DATE_STRING));
And the output is:
Mon Oct 31 13:19:56 EET 2011
rather than
Mon Oct 31 13:19:56 GMT 2011
You're printing out the result of Date.toString(). A Date doesn't have any concept of a timezone - it's just the number of milliseconds since the UTC Unix epoch. Date.toString() always uses the system default time zone.
Note that you shouldn't be expecting "Mon Oct 31 13:19:56 GMT 2011" given that you've given a time which specifies a GMT hour of 11, not 13.
If you want to use a specific time zone for printing, you should use another DateFormat for the printing, rather than using Date.toString(). (Date.toString() keeps causing confusion like this; it's really unfortunate.)
java.util.Date does not hold timezone information.
A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone.
Apart from this, there are a couple of problems with your code:
Use H instead of h for the 24-Hour format. The letter, h is used for the 12-Hour format (i.e. with AM/PM marker).
Even though MMM works for parsing the long name of the month (e.g. January) with SimpleDateFormat, it is meant for the 3-letter month name (e.g. Jan). If you try doing it with the modern Date-Time API, you will be greeted with the DateTimeParseException. You should use MMMM for the long name of the month.
Demo incorporating these points:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "31 October 2011 11:19:56 GMT";
SimpleDateFormat sdf = new SimpleDateFormat("dd MMMM yyyy HH:mm:ss z", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Date date = sdf.parse(strDateTime);
String strDate = sdf.format(date);
System.out.println(strDate);
// Some other format
sdf = new SimpleDateFormat("MMMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
strDate = sdf.format(date);
System.out.println(strDate);
// The last format with some other timezone
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
strDate = sdf.format(date);
System.out.println(strDate);
}
}
Output:
31 October 2011 11:19:56 GMT
October 31 11:19:56 GMT 2011
October 31 07:19:56 EDT 2011
ONLINE DEMO
Switch to java.time API.
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.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "31 October 2011 11:19:56 GMT";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd MMMM uuuu HH:mm:ss z", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
// Some other format
DateTimeFormatter dtfAnother = DateTimeFormatter.ofPattern("MMMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
String strDate = dtfAnother.format(zdt);
System.out.println(strDate);
}
}
Output:
2011-10-31T11:19:56Z[GMT]
October 31 11:19:56 GMT 2011
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.
* 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.

Categories