I have a small application which simply sets the time and date of a Calendar and then retrieves it.
Currently when using my application on devices up to API24 its retrieves the correct date which was originally set. But if you run the application on a device higher than API 24 then the date returned is one day later than the desired result.
My code as below
Setting the date of the calendar....
myCalendar.set(Calendar.YEAR, 2018 );
myCalendar.set(Calendar.DAY_OF_MONTH, 3);
myCalendar.set(Calendar.MONTH, 0);
myCalendar.set(Calendar.HOUR, 18);
myCalendar.set(Calendar.MINUTE, 30);
Retrieving the date
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
String dates = sdf.format(myCalendar.getTime());
StringTokenizer revDate = new StringTokenizer(dates, "/");
String txtDays = revDate.nextToken();
String txtMonths = revDate.nextToken();
String txtYears = revDate.nextToken();
String reversedDate = txtDays + txtMonths + txtYears;
On phones below API 24 we receive the correct date 03/01/2018 on API 24 above I receive 04/01/2018
I've tested my application on multiple virtual devices and real phones, all using the same time zone its only when using API 24 above that this strange issue occurs.
Thanks
I should like to contribute the modern version of your code. Barns’ answer is correct and should make sure your code behaves as it should. But I prefer:
LocalDateTime myDateTime = LocalDateTime.of(2018, Month.JANUARY, 3, 18, 30);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("ddMMuuuu");
String reversedDate = myDateTime.format(dtf);
This produces a reversedDate of 03012018 to denote 3 January 2018. If you needed the order of day-of-month, month and year reversed somehow, just modify the order in the format pattern string, for example uuuuMMdd or MMdduuuu.
I recommend the modern classes. Even though on not-too-brand-new Android devices, Calendar and SimpleDateFormat are what you get built-in, those classes are long outmoded and the latter in particular notoriously troublesome. So in my snippet I am assuming you have added ThreeTenABP to you Android project to allow you to use JSR 310, also known as java.time, the modern Java date and time API. This is so much nicer to work with. Import org.threeten.bp.LocalDateTime, org.threeten.bp.Month and org.threeten.bp.format.DateTimeFormatter. Also StringTokenizer is a legacy class. Its documentation says “It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.”
What went wrong in your code?
You haven’t given us a complete and reproducible example, so I cannot be sure, but strongly I suspect that you see the incorrect date when your code is running in the afternoon, that is at 12 noon or later in the myCalendar’s time zone (typically the JVM’s time zone, in turn typically your local time zone). Very likely myCalendar was created with the current time (Calendar.getInstance() and new GregorianCalendar(), for example, do this). In the afternoon it is obviously created with a time in PM. Then when you call myCalendar.set(Calendar.HOUR, 18), this tries to set the hour within PM, but since the hour is 18, this overflows into AM of the following day, becoming 6 AM the next day.
Links
Oracle tutorial: Date Time, explaining how to use JSR-310/java.time.
ThreeTen Backport project
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Java Specification Request (JSR) 310, where the modern date and time API was first described.
You should use "HOUR_OF_DAY" instead of "HOUR" when you set the time and you are using 24-hr system.
Try this:
myCalendar.set(Calendar.YEAR, 2018 );
myCalendar.set(Calendar.DAY_OF_MONTH, 3);
myCalendar.set(Calendar.MONTH, 0);
myCalendar.set(Calendar.HOUR_OF_DAY, 18);
myCalendar.set(Calendar.MINUTE, 30);
According to JAVA Docs:
HOUR_OF_DAY
public static final int HOUR_OF_DAY
Field number for get and set indicating the hour of the day.
HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM
the HOUR_OF_DAY is 22.
HOUR
public static final int HOUR
Field number for get and set indicating the hour of the morning or
afternoon. HOUR is used for the 12-hour clock (0 - 11). Noon and
midnight are represented by 0, not by 12. E.g., at 10:04:15.250 PM the
HOUR is 10.
I think you should use getInstance() method of calendar class because Calendar.getInstance() method gets a calendar using the specified time zone and specified locale.
for eg:
DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
Date dat = Calendar.getInstance().getTime();
String s3 = df.format(dat);
this works perfectly fine with my program and gives me desired result along with manipulation of date in the desired format.
Related
I have a streak counter that increases if an action in the app is done every day anew. I want to check it upon opening of the app, what is the easiest way?
I know I can just check in a Calendar or Date object, if it's yesterday+1, like here
Check if a date is "tomorrow" or "the day after tomorrow"
But that is not considering the time, right? Because if the action is done on 24.02. 7AM, then it would have to be 25.02. 7AM+ (24hrs) for it to work?
I know I can just check in a Calendar or Date object, if it's
yesterday+1 ...
The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
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.
But that is not considering the time, right? Because if the action is
done on 24.02. 7AM, then it would have to be 25.02. 7AM+ (24hrs) for
it to work?
The java.time API (the modern date-time API) provides you with LocalDateTime to deal with local date and time (i.e. the date and time of a place and not requiring comparing it with the date and time of another place and hence not dealing with the timezone). However, when it comes to comparing it with the date and time of another place, not in the same timezone, you need ZonedDateTime (to automatically adjust date & time object as per the DST) or OffsetDateTime (to deal with ` fixed timezone offset) etc. Given below is an overview of java.time types:
Demo:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String args[]) {
LocalDate date = LocalDate.of(2020, 2, 23);
LocalTime time = LocalTime.of(7, 0);
LocalDateTime ldt = LocalDateTime.of(date, time);
System.out.println(ldt);
LocalDateTime afterTenHoursTwentyMinutes = ldt.plusHours(10).plusMinutes(20);
LocalDateTime tomorrow = ldt.plusDays(1);
LocalDateTime theDayAfterTomorrow = ldt.plusDays(2);
System.out.println(afterTenHoursTwentyMinutes);
System.out.println(tomorrow);
System.out.println(theDayAfterTomorrow);
if (!afterTenHoursTwentyMinutes.isAfter(theDayAfterTomorrow)) {
System.out.println("After 10 hours and 20 minutes, the date & time will not go past " + tomorrow);
} else {
System.out.println("After 10 hours and 20 minutes, the date & time will go past " + tomorrow);
}
}
}
Output:
2020-02-23T07:00
2020-02-23T17:20
2020-02-24T07:00
2020-02-25T07:00
After 10 hours and 20 minutes, the date & time will not go past 2020-02-24T07:00
Learn more about the modern date-time API from Trail: Date Time.
When I create a new instance of LocalDateTime and try to get the current hour, it is off by exactly 4 hours.
For example my code will be as follows:
LocalDateTime mReminderTime = new LocalDateTime();
int mHourOfDay = mReminderTime.getHourOfDay();
The system time on the phone/tablet will be 19:00 while mHourOfDay will be 23:00. I have been testing these on physical devices.
I have also tried the following code with the same results:
LocalDateTime mReminderTime = LocalDateTime.now();
int mHourOfDay = mReminderTime.getHourOfDay();
My timezone is EST, which is -4:00 of GMT. I believe this is exactly the issue. The LocalDateTime is instantiating at 0:00 GMT causing mHourOfDay to be precisely 4 hours ahead of the system time.
My question: How do I get the LocalDateTime to initialize at EST via detecting the current timezone of the device? I don't want to set LocalDateTime to specifically use -4:00 GMT in case the user changes timezones. Right now I have a workaround solution using the Calendar as follows:
Calendar cal = Calendar.getInstance();
mReminderTime = new LocalDateTime(cal);
I was hoping to rely fully on Joda-Time, thus I wanted a solution that avoids the Calendar. If it helps, I am using this library to import Joda-Time into my project: https://github.com/dlew/joda-time-android
I want to get the current time on the device in the format: 2013-10-17 15:45:01 ?
The server sends me the date of an object in the format above as a string. Now i want to get the phones current time and then check if there is a difference of say more than 5 minutes?
So A: How can i get the devices current time in this fomat: 2013-10-17 15:45:01
B how can I work out the difference between the two.
You can use SimpleDateFormat to specify the pattern you want:
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new java.util.Date())
However, if you just want to know whether the time difference is within a certain threshold, you should probably just compare long values. If your threshold is 5 minutes, then this is 5 * 60 * 1000 milliseconds so you can use the same SimpleDateFormat by calling it's parse method and check the long values.
Example:
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2013-10-13 14:54:03").getTime()
Date currentDate = new Date(); will initialize a new date with the current time. In addition, convert the server provided time and take the difference.
String objectCreatedDateString = "2013-10-17 15:45:01";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date objectCreatedDate = null;
Date currentDate = new Date();
try
{objectCreatedDate = format.parse(objectCreatedDateString);}
catch (ParseException e)
{Log.e(TAG, e.getMessage());}
int timeDifferential;
if (objectCreatedDate != null)
timeDifferential = objectCreatedDate.getMinutes() - currentDate.getMinutes();
tl;dr
Duration.between( // Calculate time elapsed between two moments.
LocalDateTime // Represent a date with time-of-day but lacking the context of a time zone or offset-from-UTC.
.parse( "2013-10-17 15:45:01".replace( " " , "T" ) )
.atOffset( ZoneOffset.UTC ) // Returns an `OffsetDateTime` object.
.toInstant() , // Returns an `Instant` object.
Instant.now() // Capture the current moment as seen in UTC.
)
.toMinutes()
> 5
java.time
The other Answers are outdated, using terrible classes that were years ago supplanted by the modern java.time classes defined in JSR 310.
Parse your incoming string.
String input = "2013-10-17 15:45:01" ;
Modify the input to comply with ISO 8601. I suggest you educate the publisher of your data about the ISO 8601 standard.
String inoutModified = input.replace( " " , "T" ) ;
Parse as a LocalDateTime because this input lacks an indicator of the intended offset or time zone.
LocalDateTime ldt = LocalDateTime.parse( input ) ;
I assume that input was intended to represent a moment as seen in UTC, with an offset of zero hours minutes seconds. If so, educate the publisher of your data about appending a Z on the end to so indicate, per ISO 8601.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
Extract an object of the simpler class, Instant. This class is always in UTC.
Instant then = odt.toInstant() ;
Get current moment as seen in UTC.
Instant now = Instant.now() ;
Calculate the difference.
Duration d = Duration.between( then , now ) ;
Get duration as total whole minutes.
long minutes = d.toMinutes() ;
Test.
if ( minutes > 5 ) { … }
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. Hibernate 5 & JPA 2.2 support java.time.
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 brought 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 (26+) bundle implementations of the java.time classes.
For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
Use SimpleDateFromat Class
DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
dateFormatter.format(date);
Also check this documentation
If you can ask the server to send you an RFC3339 compliant date/time string, then Here is a simple answer to both of your questions:
public String getClientTime() {
Time clientTime = new Time().setToNow();
return clientTime.format("%Y-%m-%d %H:%M:%S");
}
public int diffClientAndServerTime(String svrTimeStr) {
Time svrTime = new Time();
svrTime.parse3339(svrTimeStr);
Time clientTime = new Time();
clientTime.setToNow();
return svrTime.compare( svrTime, clientTime);
}
I am storing times/dates in a database using a unix timestamp.
I want to then get all the instances on certain day so I therefore need to calculate the timestamp for the start of the day in order to query the database.
I have done a similar thing in php by passing mktime the values for the day/month/year from a date object and setting hour and minute to zero. There doesn't seem to be similar functions for this in java/android (the functions for getting the specific parts of date are deprecated)
Can anyone give some guidance on this? Thanks
Edit:
Ok so I realised this might work:
public static int startOfDay(Timestamp time) {
Calendar cal = dateToCalendar(new Date(time.getTime()));
cal.add(Calendar.HOUR_OF_DAY, -Calendar.HOUR_OF_DAY);
cal.add(Calendar.MINUTE, -Calendar.MINUTE);
cal.add(Calendar.SECOND, -Calendar.SECOND);
Log.i("Time", cal.getTime().toString());
return (int) cal.getTimeInMillis()/1000;
}
However when I ran this just now I got:
Sat Dec 15 01:24:00 GMT 2012
The seconds are right but the hour and minute are wrong??
When dealing with time, you should always consider time zones. You database timestamps should be always stored in one time zone (e.g. UTC). Your computation should then consider that users can be in different time zones and that they can change time zones.
If you want to compute start of the day in the time zone the user has currently set in his phone. Create the Calendar instance with:
Calendar cal = Calendar.getInstance();
To get the instance for a specific time zone use:
// use UTC time zone
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Then set the beginning of the day:
cal.setTime(time); // compute start of the day for the timestamp
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
public static int startOfDay(Timestamp time) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time.getTime());
cal.set(Calendar.HOUR_OF_DAY, 0); //set hours to zero
cal.set(Calendar.MINUTE, 0); // set minutes to zero
cal.set(Calendar.SECOND, 0); //set seconds to zero
Log.i("Time", cal.getTime().toString());
return (int) cal.getTimeInMillis()/1000;
}
tl;dr
ZoneId z = ZoneId.of( "America/Montreal" );
long secondsSinceEpoch = ZonedDateTime.now( z ).toLocalDate().asStartOfDay( z ).toEpochSecond() ;
Details
The accepted Answer by Tomik is correct but outdated. The troublesome old legacy date-time classes have been supplanted by the java.time classes.
As that Answer advised, you must consider time zone when getting the start of a day. 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.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( z );
Getting the first moment of the day requires going through LocalDate. The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate today = zdt.toLocalDate();
ZonedDateTime zdtTodayStart = today.atStartOfDay( z );
Note that we let java.time determine the start of day rather than assuming and hard-coding 00:00:00. Because of Daylight Saving Time (DST) and other anomalies, the day may start at another time such as 01:00:00.
Apparently, by unix timestamp you mean a count of whole seconds since the first moment of 1970 in UTC. The ZonedDateTime class has a method to give you that number. Note this may mean data loss as the ZonedDateTime may have a fraction of a second with resolution of nanoseconds.
long secondsSinceEpoch = zdtTodayStart.toEpochSecond();
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, 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….
I have been digging into the question for a while in StackOverflow
Android get Current UTC time
and
How can I get the current date and time in UTC or GMT in Java?
I have tried two ways to get the current time of my phone in GMT. I am in Spain and the difference is GMT+2. So let's see with an example:
1º attemp: I created a format and applied it to System.currentTimeMillis();
DateFormat dfgmt = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
dfgmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String gmtTime = dfgmt.format(new Date());
//Using System.currentTimeMillis() is the same as new Date()
Date dPhoneTime = dfgmt.parse(gmtTime);
Long phoneTimeUTC = dPhoneTime.getTime();
I need to substract that time to another time, that's why i do the cast to Long.
DateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date arrivalDate = df.parse(item.getArrivalDate());
//the String comes from JSON and is for example:"UTC_arrival":"2011-05-16 18:00:00"
//which already is in UTC format. So the DateFormat doesnt have the GMT paramater as dfgmt
diff = arrival.getTime() - phoneTimeUTC ;
I also tried this:
Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Long phoneTimeUTC = aGMTCalendar.getTimeInMillis()
And still I dont get the right difference. But if I do this:
Long phoneTimeUTC = aGMTCalendar.getTimeInMillis()-3600000*2;
It does work OK.
Any ideas?
Thanks a lot,
David.
This works for sure!
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(new Date())+"");
Specify the format, and you will get it in GMT!
As far as I read the calendar.getTimeInMillis(); returns the UTC time in millis. I used the following code and compared it to the Epoch in this site http://www.xav.com/time.cgi.
public int GetUnixTime()
{
Calendar calendar = Calendar.getInstance();
long now = calendar.getTimeInMillis();
int utc = (int)(now / 1000);
return (utc);
}
Giora
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Date currentLocalTime = cal.getTime();
DateFormat date = new SimpleDateFormat("dd-MM-yyy HH:mm:ss z");
date.setTimeZone(TimeZone.getTimeZone("GMT"));
String localTime = date.format(currentLocalTime);
System.out.println(localTime);
Have a look and see if that works.
you can always use:
Calendar mCalendar = Calendar.getInstance(TimeZone.getTimeZone("gmt"));
long millies = mCalendar.getTimeInMillis();
or
Calendar mCalendar = Calendar.getInstance(TimeZone.getTimeZone("utc"));
long millies = mCalendar.getTimeInMillis();
Output: 2016-08-01 14:37:48 UTC
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Works fine.
java.time and ThreeTenABP
I am providing the modern answer.
To get the difference in milliseconds between the phone time now — in Spain or any other place — and a certain time in the past:
// Example arrival time for the demonstration
Instant arrival = Instant.parse("2020-02-29T12:34:56.789Z");
Instant currentTime = Instant.now();
long difference = ChronoUnit.MILLIS.between(arrival, currentTime);
System.out.println("Difference is " + difference + " milliseconds");
Example output:
Difference is 2610350731 milliseconds
If you want the difference in seconds or some other time unit, just use the appropriate enum constant from the ChronoUnit enum instead of ChronoUnit.MILLIS.
There is no need to worry about the device time zone, nor about formatting or parsing the time, those worries only lead to over-complication of this basically simple matter.
BTW the epoch is one well-defined point in time, it doesn’t vary with time zone, it’s the same all over the world. Therefore the count of milliseconds from the epoch till now is also the same in all time zones. Some say that this count is always in UTC because the epoch is (usually) defined in UTC, as January 1, 1970 at 00:00 UTC.
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.