I am trying to calculate an offset time from a given date. I get the date as a String and parse it, and I have the offset in milliseconds. So for example
Date: 2015-08-18 00:00:00
Offset Time: 2678400000, which when applied to the date, it equals 2015-09-18 00:00:00, 31 days later.
My goal is to store each of the offsets (years/months/days/hours/minutes/seconds) in an array, so I can use it later.
However when I run this calculation using the Calendar class, I'm getting extra hours for some reason when called with offsetConverter(2678400000)
Output: 0 years 0 months 31 days 19 hours 0 minutes 0 seconds
Here is my code which I found and modified slightly from this link Best way to convert Milliseconds to number of years, months and days
public static int[] offsetConverter(long offset) {
int[] delay = new int[6];
//delay 0-3 = years/months/days/seconds
Calendar c = Calendar.getInstance();
c.setTimeInMillis(offset);
delay[0] = c.get(Calendar.YEAR) - 1970;
delay[1] = c.get(Calendar.MONTH);
delay[2] = c.get(Calendar.DAY_OF_MONTH);
delay[3] = c.get(Calendar.HOUR_OF_DAY);
delay[4] = c.get(Calendar.MINUTE);
delay[5] = c.get(Calendar.SECOND);
for (int i = 0; i< delay.length; i++)
System.out.print(delay[i] + " ");
System.out.println();
return delay;
}
If anyone sees what I'm doing wrong or has a simpler way to do this I would appreciate the help. Thanks!
Milliseconds from Date#getTime() arrive in UTC timezone, but you instantiate calendar with default timezone, which is your local. This adds extra hours to your result.
To solve this issue, create a Calendar instance using UTC timezone:
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
tl;dr
LocalDateTime.parse(
"2015-08-18 00:00:00".replace( " " , "T" ) // Convert input string to comply with ISO 8601 standard format, replacing SPACE in the middle with a `T`.
).plus(
Duration.ofDays( 31 ) // If you meant ( 31 * 24-hours ).
// Period.ofDays( 31 ) // If you meant 31 calendar-days.
// Period.ofMonths( 1 ) // If you meant a calendar-month.
) // Returns a fresh `LocalDateTime` object, distinct from original, per Immutable Objects pattern.
.toString() // Generate a string in standard ISO 8601 format to textually represent this object’s value.
2015-09-18T00:00
Terms
The word “offset” here is a poor choice of terms. That word has a specific meaning in date-time handling: the amount of hours, minutes, and seconds a time zone is from UTC. See the Wikipedia entry for UTC offset.
You seem to be concerned instead with a span of time unattached to the timeline. In the java.time classes such spans are called a Duration if in the scale of hours-minutes-seconds, and called Period if scaled in years-months-days.
java.time
The modern approach uses the java.time classes that supplanted the troublesome old date-time classes such as Date/Calendar.
Duration
Convert your span of time from a count of milliseconds to a Duration object.
Duration d = Duration.ofMillis( 2_678_400_000L );
This happens to be 744 hours.
d.toString(): PT744H
Out of curiosity, I checked the number of days in 744 hours, if we define “days” to be chunks of 24-hours.
d.toDaysPart(): 31
So it seems you really intend a month or a period of 31 days. Either way, Java has classes for that.
If you really want: ( 31 * 24 hours ), then do use a Duration. But construct the Duration object with more self-documenting code.
Duration d = Duration.ofDays( 31 ) ; // Exact same effect as `Duration.ofMillis( 2_678_400_000L )` but more clear as to your intention.
ISO 8601
Your input string almost complies with ISO 8601 standard for date-time formats. The java.time classes use the standard formats by default when parsing/generating strings.
Convert your string to comply. Replace the SPACE in the middle with a T.
String input = "2015-08-18 00:00:00".replace( " " , "T" ) ;
2015-08-18T00:00:00
LocalDateTime
Parse your input as a LocalDateTime as your input lacks an indicator of offset-from-UTC or time zone.
LocalDateTime ldt = LocalDateTime.parse( input ) ;
ldt.toString(): 2015-08-18T00:00
Add your Duration object to get a new fresh LocalDateTime. The java.time classes use immutable objects so the original object is left intact.
LocalDateTime thirtyOneTimes24HoursLaterLdt = ldt.plus( d ) ; // Adding a span-of-time to our `LocalDateTime` object to get another `LocalDateTime` object.
thirtyOneTimes24HoursLaterLdt.toString(): 2015-09-18T00:00
Be aware that LocalDateTime does not represent an actual moment, a specific point on the timeline. Without the context of a time zone or offset-from-UTC, it is only a rough idea about potential moments along a range of about 26-27 hours.
ZonedDateTime
If you know for certain your input string was meant to represent a moment in a particular zone, apply a ZoneId to get a ZonedDateTime object (an actual moment).
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; // Now we have determined an actual moment, a point on the timeline.
zdt.toString(): 2015-08-18T00:00+12:00[Pacific/Auckland]
You can add your Duration if you do not care about dates (whole days on the calendar).
ZonedDateTime thirtyOneTimes24HoursLaterZdt = zdt.plus( d ) ;
thirtyOneTimes24HoursLaterZdt.toString(): 2015-09-18T00:00+12:00[Pacific/Auckland]
If your business logic was really meant to be thirty-one days on the calendar, use a Period.
ZonedDateTime thirtyOneDaysLater = zdt.plus( Period.ofDays( 31 ) ) ;
thirtyOneDaysLater.toString(): 2015-09-18T00:00+12:00[Pacific/Auckland]
If your business logic is really intending a calendar month rather than a specific number of days, use a different Period. The class makes adjustments as needed to handle various months’ length (read the doc and follow that doc’s link).
ZonedDateTime monthLater = zdt.plus( Period.ofMonths( 1 ) ) ;
monthLater.toString(): 2015-09-18T00:00+12:00[Pacific/Auckland]
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
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
Much 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, 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.
Related
Hi i am trying to get the current year in the below code however it is returning a 1970 year instead of 2020 last month this was working correctly but since we in January 2020, it is now returning a date from 1970, please assist
public String firstDateOfNextMonth(){
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Calendar today = Calendar.getInstance();
Calendar next = Calendar.getInstance();
today.clear();
Date date;
next.clear();
next.set(Calendar.YEAR, today.get(Calendar.YEAR));
next.set(Calendar.MONTH, today.get(Calendar.MONTH)+ 1);
next.set(Calendar.DAY_OF_MONTH, 1);
date = next.getTime();
Log.d(TAG, "The Date: " + dateFormat.format(date));
return dateFormat.format(date);
}
If you have Java 8 or above, then you have java.time and you won't have to rely on outdated datetime implementations and you can do it this way:
public static String getFirstOfNextMonth() {
// get a reference to today
LocalDate today = LocalDate.now();
// having today,
LocalDate firstOfNextMonth = today
// add one to the month
.withMonth(today.getMonthValue() + 1)
// and take the first day of that month
.withDayOfMonth(1);
// then return it as formatted String
return firstOfNextMonth.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
which prints the following when called today (2020-01-03) like System.out.println(getFirstOfNextMonth());:
2020-02-01
You might have to involve an external library, the ThreeTenAbp if you want it to work in Android below API level 26. Its use is explained in this question.
not sure why the today date gets cleared, remove today.clear() at line 4
today.clear(); initalize all elements of a date with the value 0
removing this line will give you the right answer
tl;dr
LocalDate // Represent a date-only value without a time-of-day and without a time zone.
.now( // Determine the current date as seen through the wall-clock time used by people in certain region (a time zone).
ZoneId.of( "America/Montreal" ) // Real time zone names have names in the format of `Continent/Region`. Never use 2-4 letter pseudo-zones such as `IST`, `PST`, or `CST`, which are neither standardized nor unique.
) // Return a `LocalDate`.
.with( // Move from one date another by passing a `TemporalAdjuster` implementation.
TemporalAdjusters // Class providing several implementations of `TemporalAdjuster`.
.firstDayOfNextMonth() // This adjuster finds the date of the first of next month, as its name suggests.
) // Returns another `LocalDate` object. The original `LocalDate` object is unaltered.
.toString() // Generate text in standard ISO 8601 format of YYYY-MM-DD.
See this code run live at IdeOne.com.
2020-02-01
Details
You are using terrible date-time classes that were made obsolete years ago by the unanimous adoption of JSR 310 defining the java.time classes.
The Answer by deHaar is correct. Here is an even shorter solution.
TemporalAdjuster
To move from one date to another, the java.time classes include the TemporalAdjuster interface. Pass one of these objects to the with method found on many of the other java.time classes.
TemporalAdjusters.firstDayOfNextMonth()
Several implementations of that interface are found in the class TemporalAdjusters (note the s plural). One of those is firstDayOfNextMonth(), just what you need.
Get today's date. A time zone is required, as for any given moment the date varies around the globe by time zone. If omitted, your JVM's current default time zone is implicitly applied. Better to be explicit.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
LocalDate today = LocalDate.now( z ) ;
Get your TemporalAdjuster object.
TemporalAdjuster ta = TemporalAdjusters.firstDayOfNextMonth() ;
Apply that adjuster to get another LocalDate object. Note that java.time classes are immutable by design. So we get a new object rather than altering the original.
LocalDate firstOfNextMonth = today.with( ta ) ;
We can shorten this code to a one-liner, if desired.
LocalDate firstOfNextMonth =
LocalDate
.now(
ZoneId.of( "Africa/Tunis" )
)
.with(
TemporalAdjusters.firstDayOfNextMonth()
)
;
Text
Your desired output format of YYYY-MM-DD complies with the ISO 8601 standard used by default in the java.time classes when parsing/generating text. So no formatting pattern need be specified.
String output = firstOfNextMonth.toString() ;
2020-02-01
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.
You are using Calendar.clear() which clears all the fields of your calendar, and essentially reverts it to 1/1/1970 (epoch time 0).
remove today.clear() and you'll get the correct answer
see more here
Remove next.clear();. As Calendar next= Calendar.getInstance(); initiates next with the current date, in your cases Fri Jan 03 2020 15:07:53. And when you do next.clear(), it sets to the inital epoch.
Epoch, also known as Unix timestamps, is the number of seconds (not
milliseconds!) that have elapsed since January 1, 1970 at 00:00:00 GMT
(1970-01-01 00:00:00 GMT).
Hello I'm trying to convert a string in the format "17:50" to a date in android but when I try to run this code I get the correct hour from the string but the full date is from 1970. I need this date to schedule some local notifications on a given time of the day or in the next day.
String dtStart = "17:50";
SimpleDateFormat format = new SimpleDateFormat("H:mm");
try {
Calendar cal = Calendar.getInstance();
Date date = format.parse(dtStart);
cal.setTime(date);
System.out.println(cal.getTime());
} catch (ParseException e) {
e.printStackTrace();
}
Thu Jan 01 17:50:00 BRT 1970
It's not an error, your code works well. Just if you want to get current date, you have to add the difference between current day and 1st of January 1970.
Your parsed date gives you 17:30 hours, which means 17 * 60 * 60 * 1000 ms + 30 * 60 + 1000 ms.
This way you can find current day: https://stackoverflow.com/a/1908419/4142087
What Anton suggested was correct, and the current day / next day logic is your custom implementation. You have to check current time and if it past that time, jump to setting up the alarm the next day.
java.time
You need a time-of-day class to represent your intended meaning. The legacy date-time classes from the earliest versions of Java lack such a class. The java.sql.Time class pretends to do this, but actually contains a date as well due to poor design decisions.
LocalTime
You want the LocalTime class for a time-of-day value without a date and without a time zone.
It uses a generic 24-hour single-day clock. Adding/subtracting spans of time wraps around the clock since it lacks any concept of dates.
Define a formatting pattern to match your input string.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "H:mm" ) ; // Uppercase `H` means 24-hour clock, lowercase `h` means 12-hour clock.
Parse input string.
String input = "7:50" ;
LocalTime lt = LocalTime.parse( input , f ) ;
Generate a string in standard ISO 8601 format.
String output = lt.toString() ;
07:50
Perhaps your business logic requires assigning the time-of-day to a date. To determine a moment, a point on the timeline, you must also specify a time zone.
LocalDate ld = LocalDate.of( 2018 , Month.MARCH , 27 ) ;
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
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, and later
Built-in.
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
Much 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.
So I want to do something with Java GregorianCalendar that seems to be going way harder than it should. I want to get the day of the week from the month and date. But it won't do that. I know that people often get the wrong answer to this because they don't know month is numbered from 0 while DAY_OF_WEEK is numbered from 1 (like here and here). But that's not my problem. My problem is that DAY_OF_WEEK always, always, returns 7, no matter what I set the date to. When I convert the GregorianCalendar to string, DAY_OF_WEEK appears as ?, even though I have set year, month, and dayOfMonth.
The code where this is happening:
GregorianCalendar theDate;
public ObservableDate(int year, int month, int dayOfMonth, int hourOfDay, int minute, int second)
{
theDate = new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
theDate.setFirstDayOfWeek(GregorianCalendar.SUNDAY);
System.out.println("DAY_OF_WEEK = "+theDate.DAY_OF_WEEK);
System.out.println(theDate.toString());
}
The code that calls it:
ObservableDate theDate = new ObservableDate(2001, 3, 24, 9, 00, 00);
Output:
DAY_OF_WEEK = 7
java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2001,MONTH=3,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=24,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=9,HOUR_OF_DAY=9,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
Any idea why this is happening?
You are accessing the field constant instead of getting its' value. I believe you wanted to use something like,
System.out.println("DAY_OF_WEEK = " + theDate.get(Calendar.DAY_OF_WEEK));
Your problem is you're accessing the constant DAY_OF_WEEK in the Calendar class (Calendar.DAY_OF_WEEK).
To properly get the day of week use the theDate variable's .get() method like so:
theDate.get(Calendar.DAY_OF_WEEK);
tl;dr
For a smart DayOfWeek enum object.
ZonedDateTime.of( 2001 , 3 , 24 , 9 , 0 , 0 , 0 , ZoneId.of( "Pacific/Auckland" ) ) // Moment as seen by people in a certain region (time zone).
.getDayOfWeek() // Extract a `DayOfWeek` enum object to represent that day-of-week of that moment.
For a mere integer 1-7 for Monday-Sunday.
ZonedDateTime.of( 2001 , 3 , 24 , 9 , 0 , 0 , 0 , ZoneId.of( "Pacific/Auckland" ) )
.getDayOfWeek()
.getValue() // Translate that `DayOfWeek` object into a mere integer 1-7 for Monday-Sunday.
java.time
The modern approach uses the java.time classes that supplant the troublesome old legacy date-time classes. Calendar is replaced by ZonedDateTime.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2001 , 3 , 24 , 9 , 0 , 0 , 0 , z );
The DayOfWeek enum defines seven objects for each day of the week.
DayOfWeek dow = zdt.getDayOfWeek() ; // Get `DayOfWeek` enum object representing this moment’s day-of-week.
You can ask the DayOfWeek to localize the name of the day.
I suggest using these DayOfWeek objects across your codebase rather than mere integer numbers. But if you insist, you can get a number. Unlike in GregorianCalendar the numbers have a fixed meaning and do not vary by locale. The meaning is 1-7 for Monday-Sunday, per the ISO 8601 standard.
int dowNumber = zdt.getDayOfWeek().getValue() ; // 1-7 for Monday-Sunday per ISO 8601.
Immutable object
Note that java.time uses immutable objects. Rather than alter member variables on the object (“mutate”), calls to adjust the value results in a new object, leaving the original object unchanged.
ZonedDateTime zdtTomorrow = zdt.now( z ).plusDays( 1 ) ; // Alterations result in a new object, leaving original intact. Known as *immutable objects*.
Time zone
You failed to specify a time zone in your constructor’s arguments and in the arguments passed to new GregorianCalendar. In such cases, the JVM’s current default time zone is implicitly assigned. That default can vary by machine, and can even change at any moment during runtime. Better to specify your desired/expected time zone.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-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" ) ;
Octal number literals
Beware of your 00 literal value. A leading zero means octal base-8 number rather than decimal number in Java source code. You lucked-out as octal zero is also decimal zero.
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
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
Much 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, 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 trying to calculate a date window based on 3 days prior and after the current plus 30,60,90 days. I really don't no a correct way to do it with calendar this is besides this dirty way.
public static void main(String []args) throws ParseException {
Calendar cal = GregorianCalendar.getInstance();
System.out.println("Curent date is " + cal.getTime() + "\n");
int [] remainingPeriodArr = {30,60,90,180};
int [] expiredArr = {30,60,90};
for(int i = 0; i < remainingPeriodArr.length; i++) {
getSupportPeriod(remainingPeriodArr[i]);
}
for(int i = 0; i < expiredArr.length; i++) {
getSupportPeriod(expiredArr[i]);
}
}
public static void getSupportPeriod(int period) {
Calendar c1 = GregorianCalendar.getInstance();
c1.add(Calendar.DATE, -3);
c1.add(Calendar.DATE, period);
System.out.println( period + " days from prior window " + c1.getTime() + "\n");
Calendar c2 = GregorianCalendar.getInstance();
c2.add(Calendar.DATE, 3);
// Date d2 = c2.getTime();
c2.add(Calendar.DATE, period);
System.out.println( period+ " days in the future window " + c2.getTime() + "\n");
}
}
Barring the new JDK8 date library or Joda Time, the easiest is to work off the current time in milliseconds:
long now = System.currentTimeMilliseconds();
long threeDaysAgoMillis = now - (3 * 24 * 60 * 60 * 1000);
long nowPlus30Millis = now + (30 * 24 * 60 * 60 * 1000);
Date threeDaysAgo = new Date(threeDaysAgoMillis);
Date nowPlus30 = new Date(nowPlus30Millis);
If you're using JDK8, check out this tutorial. If you can use Joda time, look here.
If you go the old JDK way then be aware of following pitfalls:
A) Avoid inherited static methods in general, but use the concrete value object type.
Calendar c1 = GregorianCalendar.getInstance();
Better use:
GregorianCalendar c1 = new GregorianCalendar();
Why? If you are in Thailand you will not get the gregorian calendar with your approach by using a static Calendar-method on GregorianCalendar-class. Instead you get the buddhist calendar.
B) Use domain specific type dependent on your problem
Unfortunately GregorianCalendar is not a date-only type so it does not fit well your requirements for date arithmetic. And in old JDK there is no such type at all so you have to live with ugly work-arounds. In Java 8 you can use java.time.LocalDate, in JodaTime you can use org.joda.time.LocalDate. In my coming time library you can use net.time4j.PlainDate (first release still this month).
C) Otherwise try to mimic a plain date type
Using GregorianCalendar you need to zero out all time fields, that is:
gcal.set(year, month, dayOfMonth);
gcal.set(Calendar.HOUR_OF_DAY, 0);
gcal.set(Calendar.MINUTE, 0);
gcal.set(Calendar.SECOND, 0);
gcal.set(Calendar.MILLISECOND, 0);
Note that this approach is not perfect under some rare conditions related to time zone offset changes, but will probably be sufficient in US and Europe.
If you evaluate such calendar objects as result of addition operations like add(Calendar.DATE, period), you should only print its date part and ignore the time part - in most cases by selecting a date-only format according to your local or as ISO-8601-format (mostly limited to year, month, day-of-month).
If you compare such calendar objects then don't apply comparisons based on the method getTime(), but only by explicit extracting year, month and day-of-month (writing a specialized Comparator is a good idea).
D) Avoid self-made date/time-arithmetic, trust the library
Code like long nowPlus30Millis = now + (30 * 24 * 60 * 60 * 1000); will probably fail if you have a daylight-saving switch in the meantime. The add()-method of java.util.GregorianCalendar can take this in account, but in general not self-made arithmetic.
tl;dr
LocalDate.now().plusDays( 3 )
java.time
The modern approach uses the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without 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, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-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 ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the JVM’s current default is applied implicitly. Better to be explicit, as the default may be changed at any moment during runtime by any code in any thread of any app within the JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Or specify a date. You may set the month by a number, with sane numbering 1-12 for January-December.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Or, better, use the Month enum objects pre-defined, one for each month of the year. Tip: Use these Month objects throughout your codebase rather than a mere integer number to make your code more self-documenting, ensure valid values, and provide type-safety.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Math
One way to add days is with the LocalDate::plusDays method. Similar for subtraction.
LocalDate later = ld.plusDays( 3 ) ;
LocalDate earlier = ld.minusDays( 3 ) ;
Or, use objects to represent the span-of-time to be added or subtracted. This has the advantage of being able to label your span-of-time with variable name. For years-months-days, use Period. For hours-minutes-seconds, use Duration.
Period periodBookIsLate = Period.ofDays( 3 ) ;
LocalDate dueDate = ld.plus( periodBookIsLate ) ;
LocalDateRange
You may find the LocalDateRange class useful, available from the ThreeTen-Extra project.
LocalDateRange thirtyDayRange = LocalDateRange.of( ld.minusDays( 30 ) , ld.plusDays( 30 ) ) ;
Learn about the handy methods in that class such as abuts, contains, intersection, and more.
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
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
Much 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, 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 am using the compareTo method in Java to try and check if a certain date is greater than or equal than 24 hours after another date.
How do I determine what integer to compare the date to?
Use the Calendar class. If you already have a Date object, you can still use Calendar:
Date aDate = . . .
Calendar today = Calendar.getInstance();
today.setTime(aDate);
Calendar tomorrow = Calendar.getInstance();
tomorrow.setTime(aDate);
tomorrow.add(Calendar.DAY, 1);
Date tomorrowDate = tomorrow.getTime(); // if you need a Date object
Answer depends on what you want to achieve.
One way, could be checking difference in milliseconds. 24 h in milliseconds can be calculated via
24 * 60 * 60 * 1000 = 86400000
h min sec millis
(in code you can also write TimeUnit.HOURS.toMillis(24) which IMO is more readable)
So now you can just check if difference between two dates (expressed in milliseconds) is greater than 86400000.
tl;dr
myUtilDate_B
.toInstant()
.equals(
myUtilDate_A.toInstant().plus( 24 , ChronoUnit.HOURS )
) // Exactly 24 hours apart.
…and…
myUtilDate_B
.toInstant()
.isAfter(
myUtilDate_A.toInstant().plus( 24 , ChronoUnit.HOURS )
) // Over 24 hours apart.
Alternatively…
Duration.between( myUtilDate_A , myUtilDate_B )
.compareTo( Duration.ofHours( 24 ) )
// Returns 0 if exactly 24 hours apart,
// >0 if over 24 hours apart.
java.time
You specifically asked for comparing two date-times to ask if either:
Is one exactly 24 hours later than another
Is one more than 24 hours later than another.
The compareTo method you mentioned does not do this. It is designed to merely tell if a moment is the same, later, or sooner. The method does not care about specific spans of time such as 24 hours.
You specifically stated that the date does not matter. So you want to ignore anomalies such as Daylight Saving Time (DST) that make a day longer or shorter than 24 hours.
So we can work in UTC. No need for time zones.
If you were referring to java.util.Date objects, first convert them to java.time objects. The Date class is part of the troublesome old date-time classes, along with Calendar, that are now legacy, supplanted by the java.time classes.
The equivalent of java.util.Date is java.time.Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
You can convert to/from java.time types via new methods added to the old classes.
Instant start = myUtilDate_Start.toInstant();
Instant stop = myUtilDate_Stop.toInstant();
Define the gap we care about, in this case twenty four hours, as a Duration object.
Duration d = Duration.ofHours( 24 ); // We mean literally 24 hours, not a day.
Use that Duration to calculate the 24-hours-later value. Define the unit of hours by the ChronoUnit enum.
Instant target = start.plus( 24 , ChronoUnit.HOURS );
Lastly, compare the second date-time value. Call equals and isAfter.
Boolean isExactly24HoursLater = stop.equals( target );
Boolean isOver24HoursLater = stop.isAfter( target );
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.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
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.
Joda-Time
UPDATE: The Joda-Time project, now in maintenance mode, advises migration to the java.time classes. This section is left here intact for history.
Joda-Time makes this work easier.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime dateTimeInQuestion = new DateTime( 2014, 1, 2, 3, 4, 5, 6, timeZone ); // Or: new DateTime( someJavaDotUtilDotDateObject );
DateTime now = new DateTime( timeZone );
DateTime twentyFourHoursFromNow = now.plusHours( 24 ); // Ignores Daylight Saving Time (DST). If you want to adjust for that, call: plusDays( 1 ) instead.
DateTime isDateTimeInQuestionAfter24HoursFromNow = dateTime.isAfter( twentyFourHoursFromNow );
1 Day ≠ 24 Hours
If you really meant to consider the same wall-clock time of the next day, call plusDays( 1 ) rather than plusHours( 24 ). Joda-Time then adjusts for Daylight Saving Time (DST) or other anomalies. For example, here in the United States, that might mean 25-hours rather than 24-hours because of our 1-hour DST silliness.
Compare Within 24-Hours
If really meant to test if the date-time in question lands within that 24-hour span of time, use one of Joda-Time's three classes for spans of time: Interval, Duration, and Period.
Interval interval = new Interval( now, twentyFourHoursFromNow );
boolean isDateTimeInQuestionContainedWithinNext24Hours = interval.contains( dateTimeInQuestion );
For that kind of comparison, Joda-Time uses "Half-Open" logic. This means the beginning date-time is inclusive while the ending is exclusive. In other words, comparing for GREATER THAN OR EQUAL TO (>=) the start, but LESS THAN (<) the ending. This approach usually makes the most sense when working with date-time.
This will help you check if your date was yesterday
public static final long ONE_MINUTE = 60 * 1000;
public static final long ONE_HOUR = 60 * ONE_MINUTE;
public static final long ONE_DAY = 24 * ONE_HOUR;
public static boolean isYesterday(Date d) {
return DateUtils.isToday(d.getTime() + ONE_DAY);
}
In your Activity OnCreate
//Get current date - yymmdd increases only
SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
Date now = new Date();
int nowTime= Integer.parseInt(formatter.format(now));
//Get last login date - stored in db
int lastLogin= dbManager.getLastLoginDate();
//Check if next day
if(nowTime> lastLogin){
//Do your stuff
//Update last login date
dbManager.saveLoginDate(nowTime);
}
To find the delta between dates: In short,
long endL = end.getTimeInMillis() + end.getTimeZone().getOffset( end.getTimeInMillis() );
long startL = this.getTimeInMillis() + this.getTimeZone().getOffset(this.getTimeInMillis());
return (endL - startL) / MILLISECS_PER_DAY;
In detail,
http://user.xmission.com/~goodhill/dates/deltaDates.html