I am using the Calendar object as follows:
Calendar calendar = new GregorianCalendar();
calendar.set(Calendar.HOUR_OF_DAY, 24);
calendar.get(Calendar.HOUR_OF_DAY)
I want the result of this to be 24, as opposed to 0. Is this possible?
First of all, the time 24:00 is a valid time according to ISO-8601 and means midnight start at the next day.
java.util.GregorianCalendar does not support the hour 24. Please feel free to study following example code with my comments:
// By default lenient behaviour with overflow of 24:00 to next day
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
GregorianCalendar gcal = new GregorianCalendar(2014, Calendar.AUGUST, 17, 0, 0, 0);
gcal.set(Calendar.HOUR_OF_DAY, 24);
System.out.println("HOUR_OF_DAY: " + gcal.get(Calendar.HOUR_OF_DAY)); // 0
System.out.println(sdf.format(gcal.getTime())); // 2014-08-14 00:00
// now switch to strict mode
gcal.setLenient(false);
gcal.set(Calendar.HOUR_OF_DAY, 24);
gcal.getTime(); // triggers recomputation which will fail with following abort
// abort relates to set()-method => java.lang.IllegalArgumentException: HOUR_OF_DAY
Most other libraries do not support setting the time to 24:00, too. Neither Java-8-time nor its predecessor Joda-Time give support. However, Java-8-time can parse such times but never set.
My library Time4J partially allows setting this time, namely for the type PlainTime which indeed has an extended value range from 00:00 until 24:00 (inclusive). However, I have decided to handle it differently for the type PlainTimestamp(combination of calendar date and wall time) because I want to preserve a bijective unique mapping between timestamp and a single incrementing counter (otherwise the values 2014-08-17 24:00 and 2014-08-18 00:00 would stand for the same timestamp counter causing problems in sorting). The Time4J-solution for this problem is here automatic normalization (with overflow similar to lenient behaviour in the class GregorianCalendar).
If you set the field Calendar.HOUR_OF_DAY to be 24, then it is set to 0 of the next day.
the 24th hour of a day does not exist.
I think the command
Calendar.get(Calendar.HOUR_OF_DAY);
does the conversion from am/pm to 24H so you don't need to add anything else.
Related
Based on Epoch seconds, I convert it to the start of hour and end of hour.
long epochSeconds = 1589374800L;
Instant instant = Instant.ofEpochSecond(epochSeconds);
Calendar now = Calendar.getInstance(TimeZone.getTimeZone(ZoneId.of("Asia/Kolkata")));
now.setTimeInMillis(instant.toEpochMilli());
System.out.println(now.getTime()); // Correct --> Wed May 13 06:00:00 PDT 2020
Calendar endOfHour = (Calendar)now.clone();
endOfHour.set(Calendar.MINUTE, 59);
endOfHour.set(Calendar.SECOND, 59);
endOfHour.set(Calendar.MILLISECOND, 999);
System.out.println(endOfHour.getTime()); // Wrong ---> Wed May 13 06:29:59 PDT 2020
The start of hour seems correct, but the end of hour is not giving it right, instead of upto 59 minute, 59 second, 999 millisecond it is giving only half hour difference.
You are mixing java.time and java.util.Calendar types. Don't do that. For one thing, you're losing the TimeZone you specified when you clone. Basically, Calendar is a mess. But you don't need it here, something like
long epochSeconds = 1589374800L;
LocalDateTime date = Instant.ofEpochSecond(epochSeconds) //
.atZone(ZoneId.of("Asia/Kolkata")) //
.toLocalDateTime();
System.out.println(date);
LocalDateTime endOfHour = date.withMinute(59) //
.withSecond(59) //
.with(ChronoField.MILLI_OF_SECOND, 999);
System.out.println(endOfHour);
Should meet your needs. Here that outputs
2020-05-13T18:30
2020-05-13T18:59:59.999
Two points (and one more at the end):
Just repeating what has already been said: don’t mix old and modern date-time classes. Use the modern ones exclusively. Forget about the old ones. They were always poorly designed anyway.
Your observed result is correct and as should be expected.
You are using Asia/Kolkata time zone for your (outmoded) Calendar object. Asia/Kolkata time zone is special in that it is not offset a whole number of hours from UTC as most time zones are, but +05:30, five and a half hours. Let’s look at your times in this time zone first. Your epoch second value (AKA Unix timestamp) is equal to 2020-05-13T18:30:00+05:30 in Asia/Kolkata. The end of that hour in Asia/Kolkata is 2020-05-13T18:59:59.999. This is the result that you get.
It seems that you are running your program on a JVM in a different time zone (perhaps America/Vancouver or America/Los_Angeles). This time zone is offset a whole number of hours from UTC, so 18:59:59.999 in India equals 06:29:59 PDT (your time zone).
Half-open:
I promised you a third point. Represent the end of the hour as the whole hour, here 19:00 rather than 18:59:59 and some number of 9s. The philosophical argument: The hour doesn’t end one millisecond before the next hour begins, so this is incorrect. The practical argument: It frees you from deciding how many 9s you need. java.time has nanosecond precision, so is able to represent nearly a million points in time between your end of the hour and the beginning of the next hour. You risk hitting such a point and assigning it to the wrong hour. In comparisons just make sure that you are checking whether a point in time is strictly before the whole hour where the hour ends.
If you do need Calendar objects for a legacy API:
ZoneId zone = ZoneId.of("Asia/Kolkata");
long epochSeconds = 1589374800L;
ZonedDateTime now = Instant.ofEpochSecond(epochSeconds).atZone(zone);
Calendar nowAsOldfashionedCalendar = GregorianCalendar.from(now);
ZonedDateTime endOfHour
= now.plusHours(1).truncatedTo(ChronoUnit.HOURS).minusNanos(1);
Calendar endOfHourAsOldfashionedCalendar = GregorianCalendar.from(endOfHour);
I included .minusNanos(1) to get the last nanosecond of the previous hour, but as I said, you should prefer to omit it if you can. The conversion to GregorianCalendar will truncate to milliseconds and give you the same result as in your code in the question.
I need to change the time of a date to 23.59.
I can do it but the fast time remain the same so the date is actually not changed.
*start is my starting date exemple 6th december 2017 at 9.31am
Calendar calendar = Calendar.getInstance();
calendar.setTime(start);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
start = calendar.getTime();
I have start date at 6th december 2017 at 23.59am but the fast time is still the same.
How can I do?
I recommend you stop using the Calendar class and use java.time, the modern Java date and time API for your task:
ZonedDateTime dateTime = ZonedDateTime.of(
2017, 12, 6, 9, 31, 0, 0, ZoneId.of("Canada/Newfoundland"));
// to change time to 0:00:00
dateTime = dateTime.truncatedTo(ChronoUnit.DAYS);
System.out.println("Changed to 0:00: " + dateTime);
// to change to end of day
dateTime = dateTime.with(LocalTime.MAX);
System.out.println("Changed to end of day: " + dateTime);
// if you need it without seconds
dateTime = dateTime.truncatedTo(ChronoUnit.MINUTES);
System.out.println("Changed to 23:59: " + dateTime);
This prints
Changed to 0:00: 2017-12-06T00:00-03:30[Canada/Newfoundland]
Changed to end of day: 2017-12-06T23:59:59.999999999-03:30[Canada/Newfoundland]
Changed to 23:59: 2017-12-06T23:59-03:30[Canada/Newfoundland]
The classes Date and Calendar are long outmoded. java.time is so much nicer to work with (it is also known as JSR-310).
I recommend you specify explicitly which time zone you want your time in. So fill in yours unless it happens to be Canada/Newfoundland. To use your JVM’s time zone setting use ZoneId.systemDefault(), but beware that this setting may be changed by other parts of your program or other programs running in the same JVM.
In case start is a Date you got from a legacy API that you do not want to change just now, start by converting it to java.time.Instant and do the remainder of your operations from there:
ZonedDateTime dateTime = start.toInstant().atZone(ZoneId.of("Canada/Newfoundland"));
The rest is the same as above. If the opposite was the case, you need to pass a Date to a legacy API at the end, the opposite conversion is:
start = Date.from(dateTime.toInstant());
What went wrong in your code?
There’s is nothing wrong with your code. At least on my computer it behaves as expected. I would be very surprised if it didn’t on yours. A bit of speculation: You may have noticed that the first and the last digits of the value of start.fastTime were the same, and this could have fooled you into thinking the value had not changed. If this was the problem, it may help you to add this line:
calendar.set(Calendar.MILLISECOND, 0);
This will make sure that fastTime ends in at least five zeroes, for example 1513206000000, and it will be more conspicuous that it has changed. Fortunately, the modern API offers the truncatedTo method, an easy way to obtain zeroes on the last places of your milliseconds value.
Links
Oracle tutorial trail: Date Time
Java Specification Request (JSR) 310
In Android, I am using java.util.Calendar to get yesterday date in format yyyy-MM-dd'T'hh:mm:ss'Z'. For example if today is 31 May 2017, I want to get yesterday date as 2017-05-30T00:00:00Z.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
// Date End = yesterday
calendar.add(Calendar.DATE, -1);
Date dateEnd = calendar.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
this.dateEndStr = formatter.format(dateEnd);
I am expecting output to be 2017-05-30T00:00:00Z. But it gives me 2017-05-30T12:00:00Z.
What is wrong here? Is it TimeZone related? My timezone is GMT/UTC + 08:00 hour.
I am probably answering more than you asked about, but now you have asked, why not take all of it? I see two or three things wrong with your code. bowmore in another answer has touched on all three already, but I think a couple of them can be made a little clearer still:
Yes, the first and most serious is time zone related. You need to decide, and you should make explicit in your code, which time zone you use. And it is incorrect to give Z as time zone on a time at zone offset +08:00. Z is for Zulu time, another name for UTC.
In your format pattern, you should use capital HH for hour of day.
You should prefer the modern date and time classes, in principle always, but at least for a case like this. With these you won’t be able to make the errors you did with the oldfashioned SimpleDateFormat.
Time zone
Time zone is crucial to your task. You need to decide whether yesterday’s date in UTC (as your requested output says), in GMT/UTC + 08:00 or, say, in the the JVM’s current time zone (which can be changed at any time while your program is running). This snippet uses UTC:
this.yesterdayAtStartOfDay = LocalDate.now(ZoneOffset.UTC)
.minusDays(1)
.atStartOfDay(ZoneOffset.UTC)
.format(DateTimeFormatter.ISO_INSTANT);
Running it just now, the result is
2017-05-30T00:00:00Z
Instead of the last line of the snippet, you may use the even simpler:
.toString();
This gives the same result because atStartOfDay() gives a ZonedDateTime with time zone Z, and its toString() method gives the ISO 8601 string you requested.
If you want yesterday’s date in another time zone, in the first line of the snippet (and only the first line) use for example ZoneOffset.ofHours(8), ZoneId.of("Asia/Hong_Kong") or ZoneId.systemDefault() as time zone.
In case you are using Java 6 or 7, to use the modern date and time classes you need to get the ThreeTen-Backport library. Even though I always think twice before introducing an external dependency, I recommend this one warmly for your task.
That back-port is further adapted for Android in the ThreeTenABP project.
This is simply a mistake in your SimpleDateFormat.
You use hh for the hours, but that shows the one based hour of AM/PM.
These are the relevant symbols (from SimpleDateFormat)
H Hour in day (0-23)
k Hour in day (1-24)
K Hour in am/pm (0-11)
h Hour in am/pm (1-12)
You want this : "yyyy-MM-dd'T'HH:mm:ss'Z'"
Remark
You say your timezone is +08:00 hours, and you calculate the date using that timezone, however you format it as if it's in the Zulu timezone (which has an offset of +00:00)
BONUS
In Java 8 all this Calendar manipulating goes away :
ZonedDateTime yesterday = ZonedDateTime.now().with(ChronoField.NANO_OF_DAY, 0).minusDays(1);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
dateEndStr = formatter.format(dateEnd);
cal.add(Calendar.DAY_OF_YEAR, -1);
To subtract days, you should use:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, -5);
I'm trying to get the date and time of the first day of the prior month; specifically as it is January I'm trying to get: Sun Dec 01 00:00:00 EST 2013. I am using the below code snippet which I have modified from another found here on Stackoverflow while researching this subject; this code snippet will return: Sun Dec 01 12:00:00 EST 2013. I do not understand why setting the minimum hour for the 1st in fact returns noon.
Calendar aCalendar = Calendar.getInstance();
// add -1 month to current month
aCalendar.add(Calendar.MONTH, -1);
// set DATE to 1, so first date of previous month
//aCalendar.set(Calendar.DATE, 1);
aCalendar.set(Calendar.DATE, aCalendar.getActualMinimum(Calendar.DAY_OF_MONTH));
aCalendar.set(Calendar.HOUR, aCalendar.getActualMinimum(Calendar.HOUR));
aCalendar.set(Calendar.MINUTE, aCalendar.getActualMinimum(Calendar.MINUTE));
aCalendar.set(Calendar.SECOND, aCalendar.getActualMinimum(Calendar.SECOND));
Date firstDateOfPreviousMonth = aCalendar.getTime();
If I modify the following line as shown and set 0 I get the same result:
aCalendar.set(Calendar.HOUR, 0);
If I modify it as follows I get 1pm:
aCalendar.set(Calendar.HOUR, 0);
Result: Sun Dec 01 13:00:00 EST 2013
From the Java Docs
HOUR Field number for get and set indicating the hour of the morning
or afternoon.
You'll want to use HOUR_OF_DAY instead
HOUR_OF_DAY Field number for get and set indicating the hour of the
day.
Or set the AM_PM accordingly...
AM_PM Field number for get and set indicating whether the HOUR is
before or after noon.
In any case, take the time to consult the Java Docs
Some example code using Joda-Time 2.3.
Using default time zone, we create a DateTime instance of now (current moment), go back to previous month (in a smart manner, compensating for short month like February), get the first of month by asking for "minimum value", and then get first moment of that first-of-month day.
org.joda.time.DateTime startOfPreviousMonth = new org.joda.time.DateTime().minusMonths(1).dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
Note the method withTimeAtStartOfDay to get the first moment of the day. That moment may or may not be 00:00:00 in local time (because of Daylight Saving Time or other anomalies).
Using explicit time zone (almost always a better practice)…
DateTimeZone timeZone = DateTimeZone.forId( "Europe/Paris" ); // "Asia/Kolkata" etc.
org.joda.time.DateTime startOfPreviousMonth = new org.joda.time.DateTime( timeZone ).minusMonths(1).dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
Get a string…
String string = startOfPreviousMonth; // or startOfPreviousMonth.toString();
To convert back to a java.util.Date instance for communicating with other libraries…
java.util.Date date = startOfPreviousMonth.toDate();
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