What is the difference between the two dates below in practice?
Date date = new Date();
Date date = Calendar.getInstance().getTime();
What I understand is that new Date() is a UTC/GMT based date while calendar's getTime() is based on TimeZone & System time. Am I right? Do I miss something still?
Moreover, if my above understanding is correct, can I say that the end results of the following two functions are exactly the same ?
1.
public String getDate1(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//I set the time zone & pass the new Date()
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(new Date());
}
2.
public String getDate2(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//I didn't set the time zone because I think calendar instance will handle timezone change
return sdf.format(Calendar.getInstance().getTime());
}
I appreciate if you could point out where I understand wrongly & explain to me clearly. Because I feel this thing is confused to me. Thanks!
Practical info about Java Calendar and Date
If you want to operate with different dates in your Java program you will use Java Calendar class.
I will try to give you some overview of not widely known facts about Java Calendar and Date classes, working code examples, which you can try right away.
The basic information about Calendar class is provided by Java API. The Calendar class is about days, months and years. One could ask: is not Date class about the same? Not exactly...
What is difference between Java Date and Calendar classes?
The difference between Date and Calendar is that Date class operates with specific instant in time and Calendar operates with difference between two dates. The Calendar class gives you possibility for converting between a specific instant in time and a set of calendar fields such as HOUR, YEAR, MONTH, DAY_OF_MONTH. You can also manipulate with the calendar fields, for example getting the date of your grandmother birthday :).
I would like to point some things about Calendar and Date which you should know and which are not obvious...
Leap seconds.
Years, months, dates and hours are in "normal" range like:
A year y - 1900.
A month from 0 to 11
A date (day of month) from 1 to 31 in the usual manner. calendar leap seconds
An hour 0 to 23.
A minute from 0 to 59 in the usual manner.
But, attention!! A second is represented by an integer from 0 to 61. Looks strange - 61 second, but do not forget about leap second. About once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second.
Lenient fields.
Another funny feature is lenient and non-lenient fields in calendar. What is that? Example:
32 January 2006. Actually if you set your calendar lenient it will be 1 February 2006 and no problem for your program :). If it is non-lenient ArrayIndexOutOfBoundsException exception will be thrown.
Another question is 00:00 end or beginning of day? Is 00:00 A.M. or P.M.? Are midnight and noon A.M. or P.M?
Answer: 23:59 is the last minute of the day and 00:00 is the first minute of the next day. Midnight belongs to "am", and noon belongs to "pm", so on the same day, 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm.
And probably last question: what is epoch? and why this Epoch since January 1, 1970 00:00:00.000 GMT.
Actually it is Unix time, or POSIX time, is a system for describing points in time: it is the number of seconds after 00:00:00 UTC, January 1, 1970.
Wait, one question more!
"If we use the time which is counted since Epoch, how can I know which years had leap seconds and which not?"
Answer: To make life easier leap seconds are not counted. Java Date class takes actual time from OS and most of modern computers can not use leap seconds, their's internal clocks are not so precised. That's why periodical time synchronization is required.
There is no difference between at all between those two dates. (The second one is of course a bit wasteful in allocating a Calendar object that you don't use.)
An instance of java.util.Date is an absolute point in time. It has no knowledge of time zones. Setting the Default timezone on the SimpleDateFormat similarly does nothing, it uses the default by.... default!
To try to explain in different terms, the java.util.Date for
10:49 pm Dec 19, 2013 UTC
And
5:49 pm Dec 19, 2013 US Eastern Time
Is exactly the same object. The exact same java.util.Date represents both of those human-readable representations of time. The human-readable considerations only come into play when you use the formatter to turn it back and forth. (Hence why you set the timezone on the formatter, not on the date, date has no knowledge of what a timezone means.)
In 2022, you MUST use java.time classes and you can refer here to know almost everything that needs to be known about time. But if you are using Java versions older than 8, or if you are curious, read on for some high-level overview.
1. Date date = new Date(); //Thu Mar 24 04:15:37 GMT 2022
2. Date date = Calendar.getInstance().getTime(); //Thu Mar 24 04:15:37 GMT 2022
Date(Does not have a notion of timezone, and is mutable, i.e not thread-safe)
Date is sufficient if you need only a current timestamp in your
application, and you do not need to operate on dates, e.g., one-week
later. You can further use SimpleDateFormat to control the date/time
display format.
Calendar(Abstract class, concrete implementation is GregorianCalendar)
Calendar provides internationalization support. Looking into the
source code reveals that: getInstance() returns a GregorianCalendar
instance for all locales, (except BuddhistCalendar for Thai ("th_TH")
and JapaneseImperialCalendar for Japanese ("ja_JP")).
Trivia
If you look at the Date java documentation, you will see many deprecated methods and the note:As of JDK version 1.1, replaced by Calendar.XXX. This means Calendar was a failed attempt to fix the issues that Date class had.
Bonus
You might want to watch this to get some more insights of Date vs Calendar
Related
Simple question why the result is like the following for this code:
Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.HOUR, 12);
cal2.set(Calendar.AM_PM, Calendar.PM);
System.out.println(cal2.getTime().toString()); // Wed Jan 13 00:11:08 EET 2021
cal2.set(Calendar.AM_PM, Calendar.PM);
System.out.println(cal2.getTime().toString()); // Wed Jan 13 12:11:08 EET 2021
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR, 12);
cal.set(Calendar.AM_PM, Calendar.AM);
System.out.println(cal.getTime().toString()); // Tue Jan 12 12:11:08 EET 2021
cal.set(Calendar.AM_PM, Calendar.AM);
System.out.println(cal.getTime().toString()); // Tue Jan 12 00:11:08 EET 2021
The first looks like it is 12 at midnight not afternoon.
The third one looks like it is 12 afternoon, not midnight
Why setting calendar AM or PM multiple times change the result?
How to set the time correctly?
Calendar is very confusing
You are so far from the first being confused about how the Calendar class works. Fortunately the class is also long outdated. You should not use it.
Why setting calendar AM or PM multiple times change the result? …
To answer your question as asked, Andi80 is correct in the other answer and the comments to it: HOUR goes from 0 through 11. The documentation says about HOUR:
Field number for get and set indicating the hour of the morning or
afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and
midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the
HOUR is 10.
When you first set hour to 12 and AM/PM to PM, one should have expected an exception because the hour value is out of range. But no, a Calendar object with default settings doesn’t give you that. Instead it sets the time to 0 AM the following day; Jan 13 when you ran the code on Jan 12. By Calendar logic hour 12 is the hour that comes after hour 11.
When you set PM again, Calendar takes off from the time you had already got, which is in AM, and changes it into PM, so you get 12:11:08, still on Jan 13, the following day.
Why does it calculate the time twice? Not once and not three times when you do three calls to set()? It’s another confusing trait of Calendar. It calculates the time when you call getTime() (and some designated other methods). At that point it picks up all the changes from the calls to set() up to that point and combines them to the best of its abilities, discarding some if there are conflicts, using rules that no person in their right mind will want to understand.
The case for AM is similar, so I leave the details to the reader.
java.time
… How to set the time correctly?
I recommend that you use java.time, the modern Java date and time API, for your time work. If you just want 12 noon or 12 midnight, they are built in as constants:
LocalTime t12Noon = LocalTime.NOON;
System.out.println(t12Noon);
LocalTime t12Midnight = LocalTime.MIDNIGHT;
System.out.println(t12Midnight);
Output is:
12:00
00:00
A LocalTime is a time of day without a date.
If you have already got a time and only want to adjust the hour and AM/PM, use with():
LocalTime t12Noon = LocalTime.now(ZoneId.systemDefault())
.with(ChronoField.CLOCK_HOUR_OF_AMPM, 12)
.with(ChronoField.AMPM_OF_DAY, 1); // 1 = PM
System.out.println(t12Noon);
LocalTime t12Midnight = LocalTime.now(ZoneId.systemDefault())
.with(ChronoField.CLOCK_HOUR_OF_AMPM, 12)
.with(ChronoField.AMPM_OF_DAY, 0); // 0 = AM
System.out.println(t12Midnight);
12:47:00.665155
00:47:00.669248
If you need the date too, use ZonedDateTime or another appropriate class. All of the date-time classes of java.time that include time of day have the same with method, so the code will be the same.
If you indispensably need a Calendar object for a legacy API that you cannot afford to upgrade to java.time just now, use a ZonedDateTIme from java.time for your time math. Then use GregorianCalendar.from(ZoendDateTIme) for the conversion to a Calendar object.
Links
Documentation of Calendar.HOUR
Oracle tutorial: Date Time explaining how to use java.time.
Calendar.HOUR takes inputs in range 0-11. It will wrap around the 12 to a 0.
Use Calendar.HOUR_OF_DAY instead to use values from 0-23.
There is an anomaly I have observed while setting dates in Java.
I am trying the following:-
Date date1 = new Date("10/12/2018");
So when I am printing the date, it is coming of future
It was printing this date:- 14 June 2019.
When I am doing the following:-
Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse("10/12/2018");
It is showing the exact date. Can anyone please explain why this happened?
Thanks in advance.
java.time
To hardcode a date use the following:
LocalDate date2 = LocalDate.of(2018, Month.OCTOBER, 12);
System.out.println("Harcoded date: " + date2);
You will never get in doubt which is month, day and year. Output is:
Harcoded date: 2018-10-12
You should avoid the poorly designed and long outdated Date class and even more its deprecated constructors. Instead I am using LocalDate from java.time, the modern Java date and time API. Also a LocalDate represents a calendar date (without time of day), contrary to Date, which despite its name represents a point in time.
BTW I could not reproduce your problem. I get Fri Oct 12 00:00:00 CEST 2018 (which also agrees with the documentation, though this part of the documentation is very hard to read and understand).
Link: Oracle tutorial: Date Time explaining how to use java.time.
The Date() constructor (Note: it's deprecated !) doesn't know what is month and year.
USA: MM/dd/yyyy while Europe it's dd/MM/yyyy.
In the second form you are explicit. In the the first form it picks the wrong one.
I had the below issue During daylight change CST-CDT reset.
Am getting the Input from Was8.5 server 2018-03-11-05.00 (UTC-5) as expected, but when it comes to WAS7 server, the below method returns Sun Mar 10 00.00.00 CST 2018 instead of Sun Mar 11 00.00.00 CDT 2018
/*
* Converts XMLGregorianCalendar to java.util.Date
*/
public static Date toDate(XMLGregorianCalendar calendar){
if(calendar == null) {
return null;
}
return calendar.toGregorianCalendar().getTime();
}
I know the server date/timezone reset didn’t take place properly, but in case if I want to get right Time when CST to CDT change or vise versa. How can I rewrite the code to convert XMLGregorianCalendar to java.util.Date in Java?
Something like,
If incoming request was CST(UTC-6), the toDate(XMLGregorianCalendar calendar) returns CDT (UTC-5). then I want toDate() should return CST (UTC-6).
the same way,
If incoming request was CDT(UTC-5), the toDate(XMLGregorianCalendar calendar) returns CST(UTC-6). then i want toDate() should return CDT(UTC-5).
java.util.Date doesn't have a timezone. It just have a long value that represents the number of milliseconds since unix epoch.
What you see (Sun Mar 10 00.00.00 CST 2018) is the result of toString() method, and it uses the JVM default timezone to convert the long value to a date and time in that timezone. See this article for more details:
https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/
Anyway, one way to really know what's happening is to check this long value:
long millis = calendar.toGregorianCalendar().getTimeInMillis();
And then you can print this value in UTC:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss XXX");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(sdf.format(new Date(millis)));
Or, if you use Java 8:
System.out.println(Instant.ofEpochMilli(millis));
This will tell you the UTC instant that the Date corresponds to, so you can debug your code a little better than relying on Date::toString() method, which is confusing and misleading.
Regarding your main issue, I've tried to reproduce (I'm using Java 8 because it's easier to manipulate than using Date). First I created a date/time corresponding to 2018-03-11 in UTC-05:00, and I assumed the time to be midnight:
// March 11th 2018, midnight, UTC-05:00
OffsetDateTime odt = OffsetDateTime.parse("2018-03-11T00:00-05:00");
Then I converted this to America/Chicago timezone, which is a zone that uses CST/CDT:
// get the same instant in Central Time
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("America/Chicago"));
Then I printed this:
// print the date/time with timezone abbreviation
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm xxx z", Locale.US);
System.out.println(zdt.format(fmt)); // 2018-03-10 23:00 -06:00 CST
Note that the result is 2018-03-10 23:00 -06:00 CST: March 10th in UTC-06:00.
That's because in 2018, Daylight Saving Time starts only at 2 AM of March 11th. At midnight, DST has not started yet, so the offset is still UTC-06:00.
Anyway, your conversion code is correct, because Date just represents a point in time (a count of elapsed time since epoch) and doesn't have timezone attached to it. Perhaps the problem lies somewhere, and checking the millis value might help you to understand what's going on (my guess is that XmlGregorianCalendar sets the time to midnight when it's not present, which would explain the result of Sun Mar 10 00.00.00 CST 2018).
If that helps, the exact UTC instant where DST transition occurs (March 11th 2018 at 2 AM in UTC-06:00) corresponds to the millis value 1520755200000. If your dates in March 2018 have a value lower than that, it means they're before DST starts, and they'll be in CST.
My first suggestion is that you don’t need what you are asking for. As I see it, you’ve got a date and a UTC offset, and I don’t really see that the offset adds any useful information. Just take the date. I believe what has happened was that a point in time after the transition to summer time on March 11 was stripped of the time-of-day, but the UTC offset was kept for whatever reason or maybe for no reason at all. When giving the time at start of day (00:00), the offset disagrees with your time zone of America/Chicago (or Central Time Zone, but the ID in region/city format is unambiguous and recommended).
And don’t use java.util.Date for your date. That class is long outdated. Today we have so much better in java.time, the modern Java date and time API. Furthermore its LocalDate class is better suited for a date without time-of-day because this is exactly what it is, while a Date is really a point a in time, that is, a whole different story. Depending on taste conversion from XMLGregorianCalendar can happen in two ways.
The direct way
return LocalDate.of(calendar.getYear(), calendar.getMonth(), calendar.getDay());
With your XMLGregorianCalendar of 2018-03-11-05:00 the result is a LocalDate of 2018-03-11.
The indirect way via GregorianCalendar and ZonedDateTime:
return calendar.toGregorianCalendar().toZonedDateTime().toLocalDate();
The result is the same. The advantage of the latter is you don’t need to concern yourself with the individual fields of year, month and day-of-month. Among other things this means you don’t risk putting them in the wrong order.
If you do insist on keeping the time zone or UTC offset, at least take the offset. Sun Mar 11 00.00.00 CDT 2018 doesn’t make sense because March 11 at 00:00 hours DST was not yet in effect (it began at 02:00). Such a non-existing time will just confuse everyone. Convert your calendar object to OffsetDateTime:
return calendar.toGregorianCalendar().toZonedDateTime().toOffsetDateTime();
Result: 2018-03-11T00:00-05:00. This point in time exists.:-)
Since your calendar comes from a foreign system, you will probably want to validate it since any field may be undefined and return DatatypeConstants.FIELD_UNDEFINED. When using LocalDate.of(), you may decide that its argument validation is enough since it will object to DatatypeConstants.FIELD_UNDEFINED being passed as an argument. toGregorianCalendar() on the other hand will tacitly use default values, so when using it I would consider validation indispensable.
What went wrong in your code?
I ran your code, and similarly to iolus (see the other answer) I got Sat Mar 10 23:00:00 CST 2018. This the correct point in time. As iolus also explained, this is Date.toString rendering the point in time this way. The Date object itself doesn’t have a time zone or UTC offset in it. So I should say that your code was correct. It was just you getting confused by the toString method. Many have been before you, and the good solution is to avoid the Date class completely. Also I would think that your observations have nothing to do with any difference between WAS 7 and WAS 8.5.
I am trying to convert ISO 8601 date string to epoch time. How do I handle negative dates? Is the below code correct? Should I use something else instead of simple date format library? Negative dates are for BC.
String formatString = "yyyy-MM-dd'T'hh:mm:ssX";
SimpleDateFormat formatter = new SimpleDateFormat(formatString);
Date date = formatter.parse("-2017-01-04T12:30:00+05:00");
System.out.println(date.getTime()/1000);
Answer: -125818806600L
TL;DR: No, your code is not correct. Yes, I recommend using the modern Java date and time API instead of SimpleDateFormat.
Your first issue is defining correctness for years before the common era (BCE, “before Christ”).
As I read Wikipedia, ISO 8601 does not define clearly how to interpret a date in that range. The year itself poses no great problem: “year 0000 being equal to 1 BCE”, so -1 is 2 BCE and -2017 is 2018 BCE. You may use the proleptic Gregorian calendar, produced by extending the Gregorian calendar backward to dates preceding its official introduction in 1582, but beware that this disagrees with the Julian calendar traditionally used, so when your date-time string says January 4th this is not the same day as January 4th in the history books. Also the use of negative years and the proplectic Gregorian calendar is not a requirement by ISO 8601, it is only by agreement between the parties. Reservation: I don’t know whether there is any definition of January 4, 2018 BCE in the history books; we’re way back before the introduction of the Julian calendar too (proposed by Julius Caesar in 46 BCE).
The documentation of SimpleDateFormat does not state how it handles dates before the introduction of the Gregorian calendar. It seems to depend on a Calendar object associated with the date/time formatter. Such a Calendar object would be a GregorianCalendar on most computers and JVMs, but not always. So I take it that the output from your code is not guaranteed to be the same on all computers. And a GregorianCalendar can and usually does handle dates from before pope Gregor in the Julian calendar, so I will expect that the result you got does agree with the history books, but not with ISO 8601, when it comes to establishing which day was January 4, 2018 BCE. So on these grounds I suspect that your result is not correct.
As a test I compared the output from your code with the output from a similar use of the Java date and time API. Running your code I too got -125818806600. So I tried:
System.out.println(OffsetDateTime.parse("-2017-01-04T12:30:00+05:00")
.toInstant()
.getEpochSecond());
These classes should be ISO 8601 compliant, so I would prefer this code over yours (it’s also a bit simpler). I got
-125817294600
It’s not the same, so another sign that your code does not give the correct result. The difference is 1512000 seconds, the same as 17 days 12 hours. Let me start by admitting I don’t understand. I would readily think that the difference between Julian and Gregorian calendar could account for a difference in the range of 17 or 18 days. But the 12 hours confuse me.
Edit: The 12 hours come from your use of lowercase hh in your format pattern string. Since you don’t have an AM/PM marker, you should use uppercase HH. Correcting this error, the output from your code is
-125818763400
Now the difference between your code and mine is 1468800 seconds or precisely 17 days.
hh is for hours within AM or PM in the range 1–12. Uppercase HH is for hour in day, 0–23. It’s a very common mistake with SimpleDateFormat (not with the modern classes, they catch it so you correct it). It goes unnoticed scaringly often because for most hours the result is the same; SimpleDateFormat is happy to use AM as default and parse for example 14:30 and understand it as 2:30 PM. But since the hours in your string happen to be 12, there is a difference: 12:30 AM means 0:30 in the day, where in ISO 12:30 means 12:30 PM. Hence the 12 hours error.
In my Android Application, I am trying to convert Date/Time to Milliseconds, check the below code:
public long Date_to_MilliSeconds(int day, int month, int year, int hour, int minute)
{
Calendar c = Calendar.getInstance();
c.setTimeZone(TimeZone.getTimeZone("UTC"));
c.set(year, month, day, hour, minute, 00);
return c.getTimeInMillis();
}
Problem: I am getting 1290455340800(Nov 22 14:49:00 EST 2010) for Nov 22 19:49:00 EST 2010 (i.e. 5 hours back)
FYI, I am Currently in Indian TimeZone, but application can be executed from any country. so How do i exact Convert the date/time into the Milliseconds?
This line
c.setTimeZone(TimeZone.getTimeZone("UTC"));
Is probably causing the issue. There is no need to set the TimeZone as the current default is used.
My guess is that you're calling Date_to_MilliSeconds(22, 10, 2010, 19, 49). Your code explicitly uses UTC, so it's going to treat whatever you pass it in as UTC.
Just like your previous question (which makes me tempted to close this as a duplicate) it's unclear what you're really trying to do.
If you want to provide a local time to your method, you need to specify a local time zone. If you need to use a local time in the user's time zone, try setting the time zone to TimeZone.getDefault() - although I'd expect that to be the default anyway. If you want to provide a UTC time to your method, you need to specify a UTC time zone (as you are here).
What are you really trying to do?
In this piece of code, you are getting the amount of milliseconds since 01/01/1970 00:00 in your timezone for Nov 22 19:49:00 EST 2010 in UTC timezone. Why are you setting timezone to UTC?
The 5 hours difference is the difference between UTC and EST. You can use DateFormat.parse() to parse the input date if it's a string. Or you can use the code above and pass the desired timezone in c.setTimeZone() -- put in EST instead of UTC.
I'm using this:
public String timeToString(long time, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(time + TimeZone.getDefault().getRawOffset()
+ TimeZone.getDefault().getDSTSavings());
}
I think it solves the TimeZone problems.