I want an epoch of every day at 12pm. I have tried to make a function that makes a string of date time and has to convert into an epoch but this doesn't work and also it shows 12pm to 0(zero) I don't know why
here's what I have tried but show error:
Calendar now = Calendar.getInstance();
int year = now.get(Calendar.YEAR);
int month=now.get(Calendar.MONTH)+1;
int date=now.get(Calendar.DATE);
String yearInString = String.valueOf(year);
String monthInString=String.valueOf(month);
if(monthInString.length()==1){
monthInString="0"+monthInString;
}
String dateInString=String.valueOf(date);
if(dateInString.length()==1){
dateInString="0"+dateInString;
}
int hour=now.get(Calendar.HOUR);
String hourInString=String.valueOf(hour);
int minute=now.get(Calendar.MINUTE);
String minuteInString=String.valueOf(minute);
if(minuteInString.length()==1){
minuteInString="0"+minuteInString;
}
int second=now.get(Calendar.SECOND);
String secondInString=String.valueOf(second);
String HRD=yearInString+"-"+monthInString+"-"+dateInString+" "+hourInString+":"+minuteInString+":"+secondInString;
System.out.println(HRD);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
LocalDateTime dt = LocalDateTime.parse(HRD, dtf);
Instant instant = dt.toInstant(ZoneOffset.UTC);
System.out.println(instant.toEpochMilli());
and also tried this
Date date1 = dateFormat.parse(HRD);
long epoch = date1.getTime();
System.out.println(epoch);
but show error
Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-10-06 0:29:43' could not be parsed at index 11
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:494)
at customepoch.main(customepoch.java:35)
java.time
The java.util Date-Time API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API: From the OffsetDateTime at 12 pm, you can get the corresponding Instant using OffsetDateTime#toInstant and from this Instant, you can get the epoch milliseconds.
Demo:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
OffsetDateTime todayAtNoon = OffsetDateTime.of(LocalDate.now(ZoneOffset.UTC), LocalTime.NOON, ZoneOffset.UTC);
OffsetDateTime lastDateOfMonth = todayAtNoon.with(TemporalAdjusters.lastDayOfMonth());
for (OffsetDateTime odt = todayAtNoon; !odt.isAfter(lastDateOfMonth); odt = odt.plusDays(1)) {
System.out.println(odt.toInstant().toEpochMilli());
}
}
}
Output:
1633521600000
1633608000000
1633694400000
...
ONLINE DEMO
Learn more about the modern Date-Time API from 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. Note that Android 8.0 Oreo already provides support for java.time.
What went wrong in your code?
There are already two answers showing you how to obtain the numbers you want. I am not repeating that.
Rather I am posting this answer because I sensed a curiosity: Why did your code show 12 PM as 0 (zero)? Why did you get the error (exception)? This is what I am addressing here.
First as has been said directly or indirectly you were using the Calendar class for obtaining the current time in your time zone. Calendar is poorly designed and long outdated. Don’t do that.
Your conversion from Calendar to Instant was very, very complicated. If you had got a Calendar from some legacy API and wanted to convert it (which you don’t want for your current purpose), all you had needed was:
Instant instant = now.toInstant();
That’s right, since Java 8 Calendar has got a toInstant method for the conversion. The other old date and time classes have got similar conversion methods added.
You tried:
int hour=now.get(Calendar.HOUR);
Calendar.HOUR is for hour within AM or PM from 0 though 11. This explains why you got 0 for 12 PM. Calendar.HOUR_OF_DAY is for hour of day from 0 through 23. It’s just one of the many confusing points about Calendar and one of the many reasons why I recommend you don’t use it.
You prepended month, day of month and minute with 0 to make sure you had got two digits. You didn’t do the same for hour and second. Since your hour was 0, it was only one digit and did not match HH in the format pattern, which requires two digits. This caused the exception that you reported.
You tried this formatter for parsing:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
The string you built did not include milliseconds. You should either leave out .SSS or you should add the fraction of second to your string.
This seems to conflict with your intention:
Instant instant = dt.toInstant(ZoneOffset.UTC);
Since you wanted the time in your local time zone, it should have been:
Instant instant = dt.toInstant(ZoneId.systemDefault());
Say you have your local timezone properly set for your JVM so that it is available with ZoneId.systemDefault(). Assume also you start from today (06-Oct-2021). Then your code would be:
public static void main(String[] args) {
LocalDateTime start = LocalDateTime.of(2021, Month.OCTOBER, 6, 12, 0);
for (long i = 0; i < 10; i++) {
System.out.println(
start
.plusDays(i)
.atZone(ZoneId.systemDefault())
.toEpochSecond()
);
}
}
I have a method which generates a random date and time.
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.Period;
public String getRandomFormattedDateAndTime() {
LocalDateTime date = generateRandomDateAndTimeInPast();
return formatDate(date);
}
public LocalDateTime generateRandomDateAndTimeInPast() {
return LocalDateTime.now()
.minus(Period.ofDays(
(new Random().nextInt(365 * 2))
));
}
public static String formatDate(LocalDateTime date) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT_PATTERN);
return dateTimeFormatter.format(date);
}
and the printed output is something like "2020-08-07T08:57:09Z"
However, i need to obtain the same value with time zone format 2020-08-07T10:57:09+02:00 which has the +02:00 (my local time).
I have seen several questions and pages like this, but they do not give me a clue.
I hope this is what you are looking for:
ZonedDateTime zonedDateTime = ZonedDateTime.now().minus(Period.ofDays((new Random().nextInt(365 * 2))));
System.out.println("Date Time:" + zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
Output: Date Time:2019-07-13T14:27:51.909+05:30
Note: 05:30 is my time zone (local) offset
In your example you're using the type LocalDateTime. LocalDateTime can't be formatted with timezone pattern as it doesn't contains any timezone information...
Switch to ZonedDateTime will solve your problem.
Not sure why people are involving ZonedDateTime here, but it seems to be a valid approach...
However, I want to add another one, that is the use of an OffsetDateTime.
This is an adjusted version of your method generateRandomDateAndTimeInPast:
public static OffsetDateTime generateRandomDateAndTimeInPast(int offset) {
return OffsetDateTime.now(ZoneOffset.ofHours(offset))
.minusDays(
ThreadLocalRandom.current()
.nextInt(365 * 2)
);
}
An example use could look like this, please note the implicit call to OffsetDateTime.toString() by directly System.outing the instance of OffsetDateTime. You can alter the output by calling OffsetDateTime.format(DateTimeFormatter).
public static void main(String[] args) {
OffsetDateTime odt = generateRandomDateAndTimeInPast(2);
System.out.println(odt);
}
This prints out datetimes formatted like the following (randomly generated) one:
2020-10-14T10:44:23.304+02:00
If you need a LocalDateTime (that won't contain or print any offset), you can simply get it from the OffsetDateTime like this:
LocalDateTime ldt = odt.toLocalDateTime();
A ZonedDateTime has that method, too, so if you use that or an OffsetDateTime you can always have the LocalDateTime they are based on by calling toLocalDateTime().
You have not provided the code of your method, formatDate(LocalDate). However, you have mentioned that String getRandomFormattedDateAndTime() is returning you 2020-08-07T08:57:09Z. The following method, getDateTimeInMyTz(String) provides you with what you are looking for:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getDateTimeInMyTz("2020-08-07T08:57:09Z"));
}
public static String getDateTimeInMyTz(String strDtUtc) {
Instant instant = Instant.parse(strDtUtc);
ZoneOffset offset = ZoneId.systemDefault().getRules().getOffset(instant);
return instant.atOffset(offset).toString();
}
}
Output in my timezone which has an offset of +01:00 hours:
2020-08-07T09:57:09+01:00
Usage: Replace getDateTimeInMyTz("2020-08-07T08:57:09Z") with getDateTimeInMyTz(getRandomFormattedDateAndTime()).
If you share the code of your method, formatDate(LocalDate), I can suggest further simplification.
Learn more about java.time, 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 am wondering if there is a way to get current milliseconds since 1-1-1970 (epoch) using the new LocalDate, LocalTime or LocalDateTime classes of Java 8.
The known way is below:
long currentMilliseconds = new Date().getTime();
or
long currentMilliseconds = System.currentTimeMillis();
I'm not entirely sure what you mean by "current milliseconds" but I'll assume it's the number of milliseconds since the "epoch," namely midnight, January 1, 1970 UTC.
If you want to find the number of milliseconds since the epoch right now, then use System.currentTimeMillis() as Anubian Noob has pointed out. If so, there's no reason to use any of the new java.time APIs to do this.
However, maybe you already have a LocalDateTime or similar object from somewhere and you want to convert it to milliseconds since the epoch. It's not possible to do that directly, since the LocalDateTime family of objects has no notion of what time zone they're in. Thus time zone information needs to be supplied to find the time relative to the epoch, which is in UTC.
Suppose you have a LocalDateTime like this:
LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);
You need to apply the time zone information, giving a ZonedDateTime. I'm in the same time zone as Los Angeles, so I'd do something like this:
ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));
Of course, this makes assumptions about the time zone. And there are edge cases that can occur, for example, if the local time happens to name a time near the Daylight Saving Time (Summer Time) transition. Let's set these aside, but you should be aware that these cases exist.
Anyway, if you can get a valid ZonedDateTime, you can convert this to the number of milliseconds since the epoch, like so:
long millis = zdt.toInstant().toEpochMilli();
What I do so I don't specify a time zone is,
System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());
gives
ldt 1424812121078
ctm 1424812121281
As you can see the numbers are the same except for a small execution time.
Just in case you don't like System.currentTimeMillis, use Instant.now().toEpochMilli()
Since Java 8 you can call java.time.Instant.toEpochMilli().
For example the call
final long currentTimeJava8 = Instant.now().toEpochMilli();
gives you the same results as
final long currentTimeJava1 = System.currentTimeMillis();
To avoid ZoneId you can do:
LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);
System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());
Getting 0 as value, that's right!
You can use java.sql.Timestamp also to get milliseconds.
LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
To get the current time in milliseconds (since the epoch), use System.currentTimeMillis().
You can try this:
long diff = LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
Why didn't anyone mentioned the method LocalDateTime.toEpochSecond():
LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);
This seems way shorter that many suggested answers above...
For LocalDateTime I do it this way:
LocalDateTime.of(2021,3,18,7,17,24,341000000)
.toInstant(OffsetDateTime.now().getOffset())
.toEpochMilli()
I think this is more simpler:
ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());
Assert.assertEquals(System.currentTimeMillis(), zdt.toInstant().toEpochMilli());
get the millis like System.currentTimeMillis() (from UTC).
There are some methods available that no one has mentioned here. But I don't see a reason why they should not work.
In case of LocalDate, you can use the toEpochDay() method. It returns the number of days since 01/01/1970. That number then can be easily converted to milliseconds:
long dateInMillis = TimeUnit.DAYS.toMillis(myLocalDate.toEpochDays());
Documentation can be found here.
In case of LocalDateTime, you can use the toEpochSecond() method. It returns the number of seconds since 01/01/1970. That number then can be converted to milliseconds, too:
long dateTimeInMillis = TimeUnit.SECONDS.toMillis(myLocalDateTime.toEpochSeconds());
Documentation for that is here.
If you have a Java 8 Clock, then you can use clock.millis() (although it recommends you use clock.instant() to get a Java 8 Instant, as it's more accurate).
Why would you use a Java 8 clock? So in your DI framework you can create a Clock bean:
#Bean
public Clock getClock() {
return Clock.systemUTC();
}
and then in your tests you can easily Mock it:
#MockBean private Clock clock;
or you can have a different bean:
#Bean
public Clock getClock() {
return Clock.fixed(instant, zone);
}
which helps with tests that assert dates and times immeasurably.
Date and time as String to Long (millis):
String dateTimeString = "2020-12-12T14:34:18.000Z";
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDateTime localDateTime = LocalDateTime
.parse(dateTimeString, formatter);
Long dateTimeMillis = localDateTime
.atZone(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
default LocalDateTime getDateFromLong(long timestamp) {
try {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
} catch (DateTimeException tdException) {
// throw new
}
}
default Long getLongFromDateTime(LocalDateTime dateTime) {
return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}
I want to find the difference between two Calendar objects in number of days if there is date change like If clock ticked from 23:59-0:00 there should be a day difference.
i wrote this
public static int daysBetween(Calendar startDate, Calendar endDate) {
return Math.abs(startDate.get(Calendar.DAY_OF_MONTH)-endDate.get(Calendar.DAY_OF_MONTH));
}
but its not working as it only gives difference between days if there is month difference its worthless.
Try the following approach:
public static long daysBetween(Calendar startDate, Calendar endDate) {
long end = endDate.getTimeInMillis();
long start = startDate.getTimeInMillis();
return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start));
}
In Java 8 and later, we could simply use the java.time classes.
hoursBetween = ChronoUnit.HOURS.between(calendarObj.toInstant(), calendarObj.toInstant());
daysBetween = ChronoUnit.DAYS.between(calendarObj.toInstant(), calendarObj.toInstant());
This function computes the number of days between two Calendars as the number of calendar days of the month that are between them, which is what the OP wanted. The calculation is performed by counting how many multiples of 86,400,000 milliseconds are between the calendars after both have been set to midnight of their respective days.
For example, my function will compute 1 day's difference between a Calendar on January 1, 11:59PM and January 2, 12:01AM.
import java.util.concurrent.TimeUnit;
/**
* Compute the number of calendar days between two Calendar objects.
* The desired value is the number of days of the month between the
* two Calendars, not the number of milliseconds' worth of days.
* #param startCal The earlier calendar
* #param endCal The later calendar
* #return the number of calendar days of the month between startCal and endCal
*/
public static long calendarDaysBetween(Calendar startCal, Calendar endCal) {
// Create copies so we don't update the original calendars.
Calendar start = Calendar.getInstance();
start.setTimeZone(startCal.getTimeZone());
start.setTimeInMillis(startCal.getTimeInMillis());
Calendar end = Calendar.getInstance();
end.setTimeZone(endCal.getTimeZone());
end.setTimeInMillis(endCal.getTimeInMillis());
// Set the copies to be at midnight, but keep the day information.
start.set(Calendar.HOUR_OF_DAY, 0);
start.set(Calendar.MINUTE, 0);
start.set(Calendar.SECOND, 0);
start.set(Calendar.MILLISECOND, 0);
end.set(Calendar.HOUR_OF_DAY, 0);
end.set(Calendar.MINUTE, 0);
end.set(Calendar.SECOND, 0);
end.set(Calendar.MILLISECOND, 0);
// At this point, each calendar is set to midnight on
// their respective days. Now use TimeUnit.MILLISECONDS to
// compute the number of full days between the two of them.
return TimeUnit.MILLISECONDS.toDays(
Math.abs(end.getTimeInMillis() - start.getTimeInMillis()));
}
Extension to #JK1 great answer :
public static long daysBetween(Calendar startDate, Calendar endDate) {
//Make sure we don't change the parameter passed
Calendar newStart = Calendar.getInstance();
newStart.setTimeInMillis(startDate.getTimeInMillis());
newStart.set(Calendar.HOUR_OF_DAY, 0);
newStart.set(Calendar.MINUTE, 0);
newStart.set(Calendar.SECOND, 0);
newStart.set(Calendar.MILLISECOND, 0);
Calendar newEnd = Calendar.getInstance();
newEnd.setTimeInMillis(endDate.getTimeInMillis());
newEnd.set(Calendar.HOUR_OF_DAY, 0);
newEnd.set(Calendar.MINUTE, 0);
newEnd.set(Calendar.SECOND, 0);
newEnd.set(Calendar.MILLISECOND, 0);
long end = newEnd.getTimeInMillis();
long start = newStart.getTimeInMillis();
return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start));
}
UPDATE The Joda-Time project, now in maintenance mode, advises migration to the java.time classes. See the Answer by Anees A for the calculation of elapsed hours, and see my new Answer for using java.time to calculate elapsed days with respect for the calendar.
Joda-Time
The old java.util.Date/.Calendar classes are notoriously troublesome and should be avoided.
Instead use the Joda-Time library. Unless you have Java 8 technology in which case use its successor, the built-in java.time framework (not in Android as of 2015).
Since you only care about "days" defined as dates (not 24-hour periods), let's focus on dates. Joda-Time offers the class LocalDate to represent a date-only value without time-of-day nor time zone.
While lacking a time zone, note that time zone is crucial in determining a date such as "today". A new day dawns earlier to the east than to the west. So the date is not the same around the world at one moment, the date depends on your time zone.
DateTimeZone zone = DateTimeZone.forID ( "America/Montreal" );
LocalDate today = LocalDate.now ( zone );
Let's count the number of days until next week, which should of course be seven.
LocalDate weekLater = today.plusWeeks ( 1 );
int elapsed = Days.daysBetween ( today , weekLater ).getDays ();
The getDays on the end extracts a plain int number from the Days object returned by daysBetween.
Dump to console.
System.out.println ( "today: " + today + " to weekLater: " + weekLater + " is days: " + days );
today: 2015-12-22 to weekLater: 2015-12-29 is days: 7
You have Calendar objects. We need to convert them to Joda-Time objects. Internally the Calendar objects have a long integer tracking the number of milliseconds since the epoch of first moment of 1970 in UTC. We can extract that number, and feed it to Joda-Time. We also need to assign the desired time zone by which we intend to determine a date.
long startMillis = myStartCalendar.getTimeInMillis();
DateTime startDateTime = new DateTime( startMillis , zone );
long stopMillis = myStopCalendar.getTimeInMillis();
DateTime stopDateTime = new DateTime( stopMillis , zone );
Convert from DateTime objects to LocalDate.
LocalDate start = startDateTime.toLocalDate();
LocalDate stop = stopDateTime.toLocalDate();
Now do the same elapsed calculation we saw earlier.
int elapsed = Days.daysBetween ( start , stop ).getDays ();
Here's my solution using good old Calendar objects:
public static int daysApart(Calendar d0,Calendar d1)
{
int days=d0.get(Calendar.DAY_OF_YEAR)-d1.get(Calendar.DAY_OF_YEAR);
Calendar d1p=Calendar.getInstance();
d1p.setTime(d1.getTime());
for (;d1p.get(Calendar.YEAR)<d0.get(Calendar.YEAR);d1p.add(Calendar.YEAR,1))
{
days+=d1p.getActualMaximum(Calendar.DAY_OF_YEAR);
}
return days;
}
This assumes d0 is later than d1. If that's not guaranteed, you could always test and swap them.
Basic principle is to take the difference between the day of the year of each. If they're in the same year, that would be it.
But they might be different years. So I loop through all the years between them, adding the number of days in a year. Note that getActualMaximum returns 366 in leap years and 365 in non-leap years. That's why we need a loop, you can't just multiply the difference between the years by 365 because there might be a leap year in there. (My first draft used getMaximum, but that doesn't work because it returns 366 regardless of the year. getMaximum is the maximum for ANY year, not this particular year.)
As this code makes no assumptions about the number of hours in a day, it is not fooled by daylight savings time.
tl;dr
java.time.temporal.ChronoUnit // The java.time classes are built into Java 8+ and Android 26+. For earlier Android, get must of the functionality by using the latest tooling with "API desugaring".
.DAYS // A pre-defined enum object.
.between(
( (GregorianCalendar) startCal ) // Cast from the more abstract `Calendar` to the more concrete `GregorianCalendar`.
.toZonedDateTime() // Convert from legacy class to modern class. Returns a `ZonedDateTime` object.
.toLocalDate() // Extract just the date, to get the Question's desired whole-days count, ignoring fractional days. Returns a `LocalDate` object.
,
( (GregorianCalendar) endCal )
.toZonedDateTime()
.toLocalDate()
) // Returns a number of days elapsed between our pair of `LocalDate` objects.
java.time
The Answer by Mohamed Anees A is correct for hours but wrong for days. Counting days requires a time zone. That other Answer uses the Instant which is a moment in UTC, always in UTC. So you are not getting the correct number of calendar days elapsed.
To count days by the calendar, convert your legacy Calendar to a ZonedDateTime, then feed to ChronoUnit.DAYS.between.
Time zone
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment during runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument. If critical, confirm the zone with your user.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ; // Capture the current date as seen through the wall-clock time used by the people of a certain region (a time zone).
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Convert from GregorianCalendar to ZonedDateTime
The terrible GregorianCalendar is likely the concrete class behind your Calendar. If so, convert from that legacy class to the modern class, ZonedDateTime.
GregorianCalendar gc = null ; // Legacy class representing a moment in a time zone. Avoid this class as it is terribly designed.
if( myCal instanceof GregorianCalendar ) { // See if your `Calendar` is backed by a `GregorianCalendar` class.
gc = (GregorianCalendar) myCal ; // Cast from the more general class to the concrete class.
ZonedDateTime zdt = gc.toZonedDateTime() ; // Convert from legacy class to modern class.
}
The resulting ZonedDateTime object carries a ZoneId object for the time zone. With that zone in place, you can then calculate elapsed calendar days.
Calculate elapsed days
To calculate the elapsed time in terms of years-months-days, use Period class.
Period p = Period.between( zdtStart , zdtStop ) ;
If you want total number of days as the elapsed time, use ChronoUnit.
long days = ChronoUnit.DAYS.between( zdtStart , zdtStop ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I have the similar (not exact same) approach given above by https://stackoverflow.com/a/31800947/3845798.
And have written test cases around the api, for me it failed if I passed
8th march 2017 - as the start date and 8th apr 2017 as the end date.
There are few dates where you will see the difference by 1day.
Therefore, I have kind of made some small changes to my api and my current api now looks something like this
public long getDays(long currentTime, long endDateTime) {
Calendar endDateCalendar;
Calendar currentDayCalendar;
//expiration day
endDateCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
endDateCalendar.setTimeInMillis(endDateTime);
endDateCalendar.set(Calendar.MILLISECOND, 0);
endDateCalendar.set(Calendar.MINUTE, 0);
endDateCalendar.set(Calendar.HOUR, 0);
endDateCalendar.set(Calendar.HOUR_OF_DAY, 0);
//current day
currentDayCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
currentDayCalendar.setTimeInMillis(currentTime);
currentDayCalendar.set(Calendar.MILLISECOND, 0);
currentDayCalendar.set(Calendar.MINUTE, 0);
currentDayCalendar.set(Calendar.HOUR,0);
currentDayCalendar.set(Calendar.HOUR_OF_DAY, 0);
long remainingDays = (long)Math.ceil((float) (endDateCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()) / (24 * 60 * 60 * 1000));
return remainingDays;}
I am not using TimeUnit.MILLISECONDS.toDays that were causing me some issues.
Kotlin solution, purely relies on Calendar. At the end gives exact number of days difference.
Inspired by #Jk1
private fun daysBetween(startDate: Calendar, endDate: Calendar): Long {
val start = Calendar.getInstance().apply {
timeInMillis = 0
set(Calendar.DAY_OF_YEAR, startDate.get(Calendar.DAY_OF_YEAR))
set(Calendar.YEAR, startDate.get(Calendar.YEAR))
}.timeInMillis
val end = Calendar.getInstance().apply {
timeInMillis = 0
set(Calendar.DAY_OF_YEAR, endDate.get(Calendar.DAY_OF_YEAR))
set(Calendar.YEAR, endDate.get(Calendar.YEAR))
}.timeInMillis
val differenceMillis = end - start
return TimeUnit.MILLISECONDS.toDays(differenceMillis)
}
If your project doesn't support new Java 8 classes (as selected answer), you can add this method to calculate the days without being influenced by timezones or other facts.
It is not as fast (greater time complexity) as other methods but it's reliable, anyways date comparisons are rarely larger than hundreds or thousands of years.
(Kotlin)
/**
* Returns the number of DAYS between two dates. Days are counted as calendar days
* so that tomorrow (from today date reference) will be 1 , the day after 2 and so on
* independent on the hour of the day.
*
* #param date - reference date, normally Today
* #param selectedDate - date on the future
*/
fun getDaysBetween(date: Date, selectedDate: Date): Int {
val d = initCalendar(date)
val s = initCalendar(selectedDate)
val yd = d.get(Calendar.YEAR)
val ys = s.get(Calendar.YEAR)
if (ys == yd) {
return s.get(Calendar.DAY_OF_YEAR) - d.get(Calendar.DAY_OF_YEAR)
}
//greater year
if (ys > yd) {
val endOfYear = Calendar.getInstance()
endOfYear.set(yd, Calendar.DECEMBER, 31)
var daysToFinish = endOfYear.get(Calendar.DAY_OF_YEAR) - d.get(Calendar.DAY_OF_YEAR)
while (endOfYear.get(Calendar.YEAR) < s.get(Calendar.YEAR)-1) {
endOfYear.add(Calendar.YEAR, 1)
daysToFinish += endOfYear.get(Calendar.DAY_OF_YEAR)
}
return daysToFinish + s.get(Calendar.DAY_OF_YEAR)
}
//past year
else {
val endOfYear = Calendar.getInstance()
endOfYear.set(ys, Calendar.DECEMBER, 31)
var daysToFinish = endOfYear.get(Calendar.DAY_OF_YEAR) - s.get(Calendar.DAY_OF_YEAR)
while (endOfYear.get(Calendar.YEAR) < d.get(Calendar.YEAR)-1) {
endOfYear.add(Calendar.YEAR, 1)
daysToFinish += endOfYear.get(Calendar.DAY_OF_YEAR)
}
return daysToFinish + d.get(Calendar.DAY_OF_YEAR)
}
}
Unit Tests, you can improve them I didn't need the negative days so I didn't test that as much:
#Test
fun `Test days between on today and following days`() {
val future = Calendar.getInstance()
calendar.set(2019, Calendar.AUGUST, 26)
future.set(2019, Calendar.AUGUST, 26)
Assert.assertEquals(0, manager.getDaysBetween(calendar.time, future.time))
future.set(2019, Calendar.AUGUST, 27)
Assert.assertEquals(1, manager.getDaysBetween(calendar.time, future.time))
future.set(2019, Calendar.SEPTEMBER, 1)
Assert.assertEquals(6, manager.getDaysBetween(calendar.time, future.time))
future.set(2020, Calendar.AUGUST, 26)
Assert.assertEquals(366, manager.getDaysBetween(calendar.time, future.time)) //leap year
future.set(2022, Calendar.AUGUST, 26)
Assert.assertEquals(1096, manager.getDaysBetween(calendar.time, future.time))
calendar.set(2019, Calendar.DECEMBER, 31)
future.set(2020, Calendar.JANUARY, 1)
Assert.assertEquals(1, manager.getDaysBetween(calendar.time, future.time))
}
#Test
fun `Test days between on previous days`() {
val future = Calendar.getInstance()
calendar.set(2019, Calendar.AUGUST, 26)
future.set(2019,Calendar.AUGUST,25)
Assert.assertEquals(-1, manager.getDaysBetween(calendar.time, future.time))
}
#Test
fun `Test days between hour doesn't matter`() {
val future = Calendar.getInstance()
calendar.set(2019, Calendar.AUGUST, 26,9,31,15)
future.set(2019,Calendar.AUGUST,28, 7,0,0)
Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))
future.set(2019,Calendar.AUGUST,28, 9,31,15)
Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))
future.set(2019,Calendar.AUGUST,28, 23,59,59)
Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))
}
#Test
fun `Test days between with time saving change`() {
val future = Calendar.getInstance()
calendar.set(2019, Calendar.OCTOBER, 28)
future.set(2019, Calendar.OCTOBER,29)
Assert.assertEquals(1, manager.getDaysBetween(calendar.time, future.time))
future.set(2019, Calendar.OCTOBER,30)
Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))
}
public int getIntervalDays(Calendar c1,Calendar c2){
Calendar first = cleanTimePart(c1);
Calendar second = cleanTimePart(c2);
Long intervalDays = (first.getTimeInMillis() - second.getTimeInMillis())/(1000*3600*24);
return intervalDays.intValue();
}
private Calendar cleanTimePart(Calendar dateTime){
Calendar newDateTime = (Calendar)dateTime.clone();
newDateTime.set(Calendar.HOUR_OF_DAY,0);
newDateTime.set(Calendar.MINUTE,0);
newDateTime.set(Calendar.SECOND,0);
newDateTime.set(Calendar.MILLISECOND,0);
return newDateTime;
}
Calendar day1 = Calendar.getInstance(); Calendar day2 = Calendar.getInstance(); int diff = day1.get(Calendar.DAY_OF_YEAR)
- day2.get(Calendar.DAY_OF_YEAR);