What timezone does Google Tasks use? - android

I am prototyping a Google Tasks app using the Quickstart and the API reference. No problem retrieving the tasks. The question is what timezone the Due Date is stored in? I retrieve the Due Date as a DateTime per the doc, and then convert it to a displayed value in my default (local) timezone.
Here's what I observe: a due-date such as "Wed, Oct 4" (what you would get if you moved a Task to Oct 4 on the Google Calendar) is retrieved as "Wed, Oct 4 12:00am" in UTC, so that when I convert it to my local timezone (PDT) I get "Tue, Oct 3 5:00pm".
This makes me think that Google Tasks stores all Task dates and times in UTC and then interprets them as dates and times in your local timezone (in other words, if I were in New York, it would still store Wed, Oct 4 12:00am in UTC. This is consistent with my observation that if you change timezones, Task Due Dates don't change on the Google Calendar interface.
Can anybody confirm or deny?
Here's my code snippets, basically following the quickstart.
Fetching...
private List<Task> getTasks() throws IOException {
List<Task> tasks =
mService.tasks()
.list("#default")
.setFields("items/id,items/title,items/notes,items/status,items/due,items/completed")
.execute()
.getItems();
return tasks;
}
Computing the date-time to display:
final boolean isCompleted = "completed".equals(task.getStatus());
viewHolder.mCompleteCheckbox.setChecked(isCompleted);
viewHolder.mTitle.setText(task.getTitle());
if ((task.getNotes() == null) || task.getNotes().isEmpty()) {
viewHolder.mNotes.setVisibility(GONE);
} else {
viewHolder.mNotes.setVisibility(View.VISIBLE);
viewHolder.mNotes.setText(task.getNotes());
}
final DateTime dueOrCompletedDate = isCompleted ? task.getCompleted() : task.getDue();
if (dueOrCompletedDate == null ) {
viewHolder.mDueOrCompleted.setVisibility(GONE);
} else {
viewHolder.mDueOrCompleted.setVisibility(View.VISIBLE);
final String dateTimeString = Utils.timeMillisToDefaultShortDateTime(dueOrCompletedDate.getValue());
viewHolder.mDueOrCompleted.setText(dateTimeString);
}
and the date-time conversion itself where I am now converting to UTC to get the correct dates:
public static String dateFormat = "EEE, MMM d";
public static String timeMillisToDefaultShortTime(final long timeMillis) {
DateFormat df = DateFormat.getTimeInstance(DateFormat.SHORT);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String formattedTime = df.format(timeMillis);
//TODO: Bit of a hack; Parse out p.m. and PM to hh:mmpm (to save space)
return formattedTime.replace("p.m.","pm").replace("P.M.","pm").replace("PM","pm").replace(" pm","pm")
.replace("a.m.","am").replace("A.M.","am").replace("AM","am").replace(" am","am");
}
public static String timeMillisToDefaultShortDateTime(final long timeMillis) {
String defaultShortTime = timeMillisToDefaultShortTime(timeMillis);
if (defaultShortTime.equals("12:00am")) defaultShortTime = "";
return timeMillisToDateFormat(timeMillis, dateFormat).concat(" ").concat(defaultShortTime);
}
private static String timeMillisToDateFormat(long milliSeconds, String dateFormat)
{
// Create a DateFormatter object for displaying date in specified format.
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
//FIXME: Convert to UTC
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// Create a calendar object that will convert the date and time value in milliseconds to date.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(milliSeconds);
return formatter.format(calendar.getTime());
}
UPDATE: Clear evidence that Google Tasks uses UTC regardless, here's the debug view of a Task scheduled for Oct 3:
o2 = {Task#5424} size = 4
0 = {DataMap$Entry#5501} "due" -> "2017-10-03T00:00:00.000Z"
1 = {DataMap$Entry#5502} "id" -> "MDg1MjU5NjA3OTE3MzY1OTM2MjM6MDoxNzAwMTU3NzM"
2 = {DataMap$Entry#5503} "status" -> "needsAction"
3 = {DataMap$Entry#5504} "title" -> "xxxxx"

Since you mentioned Google Calendar, I think this answers that question:
Daylight savings time
Google Calendar uses Coordinated Universal Time (UTC) to help avoid
issues with daylight savings time.
When events are created, they're converted into UTC, but you'll always
see them in your local time.
If an area switches their time zone, events created before we knew
about the change might be in the wrong time zone.

Related

Converting String to Date generates different results on different devices

I am retrieving a String called date in the form 2018-09-20T17:00:00Z for example and converting it to a Date in the format Thu Oct 20 17:00:00 GMT+01:00 2018 using
SimpleDateFormat dateConvert = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'", Locale.US);
convertedDate = new Date();
try {
convertedDate = dateConvert.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
On different devices however I am getting different results. One gives Thu Oct 20 17:00:00 BST 2018 (British Summer Time, equivalent to GMT+01:00) but this proves problematic later on. Is there a way to ensure dates are formatted in terms of a GMT offset i.e. GMT+01:00 instead of BST?
java.time
Instant convertInstant = Instant.parse(date);
An Instant (just like a Date) represents a point in time independently of time zone. So you’re fine. As an added bonus your String of 2018-09-20T17:00:00Z is in the ISO 8601 format for an instant, so the Instant class parses it without the need for specifying the format.
EDIT: To format it into a human readable string in British Summer Time with unambiguous UTC offset use for example:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
ZonedDateTime dateTime = convertInstant.atZone(ZoneId.of("Europe/London"));
String formatted = dateTime.format(formatter);
System.out.println(formatted);
This code snippet printed:
Thu Sep 20 18:00:00 +0100 2018
18:00 is the correct time at offset +01:00. The Z at the end of the original string means offset zero, AKA “Zulu time zone”, and 17 at offset zero is the same point in time as 18:00 at offset +01:00. I took over the format pattern string from your own answer.
EDIT 2
I wanted to present to you my suggestion for rewriting the Fixture class from your own answer:
public class Fixture implements Comparable<Fixture> {
private static DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
public Instant date;
/** #param date Date string from either web service or persistence */
public Fixture(String date) {
this.date = Instant.parse(date);
}
/** #return a string for persistence, e.g., Firebase */
public String getDateForPersistence() {
return date.toString();
}
/** #return a string for the user in the default time zone of the device */
public String getFormattedDate() {
return date.atZone(ZoneId.systemDefault()).format(formatter);
}
#Override
public int compareTo(Fixture other) {
return date.compareTo(other.date);
}
#Override
public String toString() {
return "Fixture [date=" + date + "]";
}
}
This class has a natural ordering (namely by date and time) in that it implements Comparable, meaning you no longer need your DateSorter class. A few lines of code to demonstrate the use of the new getXx methods:
String date = "2018-09-24T11:30:00Z";
Fixture fixture = new Fixture(date);
System.out.println("Date for user: " + fixture.getFormattedDate());
System.out.println("Date for Firebase: " + fixture.getDateForPersistence());
When I ran this snippet in Europe/London time zone I got:
Date for user: Mon Sep 24 12:30:00 +0100 2018
Date for Firebase: 2018-09-24T11:30:00Z
So the user gets the date and time with his or her own offset from UTC as I think you asked for. Trying the same snippet in Europe/Berlin time zone:
Date for user: Mon Sep 24 13:30:00 +0200 2018
Date for Firebase: 2018-09-24T11:30:00Z
We see that the user in Germany is told that the match is at 13:30 rather than 12:30, which agrees with his or her clock. The date to be persisted in Firebase is unchanged, which is also what you want.
What went wrong in your code
There are two bugs in your format pattern string, yyyy-MM-dd'T'hh:mm:ss'Z':
Lowercase hh is for hour within AM or PM from 01 through 12 and only meaningful with an AM/PM marker. In practice you will get the correct result except when parsing an hour of 12, which will be understood as 00.
By parsing Z as a literal you are not getting the UTC offset information from the string. Instead SimpleDateFormat will use the time zone setting of the JVM. This obviously differs from one device to the other and explains why you got different and conflicting results in different devices.
The other thing going on in your code is the peculiar behaviour of Date.toString: this method grabs the JVM’s time zone setting and uses it for generating the string. So when one device is set to Europe/London and another to GMT+01:00, then equal Date objects will be rendered differently on those devices. This behaviour has confused many.
Question: Can I use java.time on Android?
Yes, java.time works nicely on 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, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom). The code above was developed and run with org.threeten.bp.Duration from the backport.
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.
Wikipedia article: ISO 8601
You are just doing step 1 of a two step process:
Parse the date to convert it to a Date object
Take this parsed Date object and format it using SimpleDateFormat again.
So, you've done step one correctly, here's what you have to do with step 2, try this:
final String formattedDateString = new SimpleDateFormat("EEE MMM dd HH:mm:ss 'GMT'XXX yyyy").format(convertedDate);
Source
So just to add a bit of an update here. The answers that people have provided have helped massively and I now have a code that does exactly what I want, but the term 'legacy' in one of the comments makes me feel that there may be a better and longer-lasting way. Here's what currently happens in the code.
1) I fetch a football fixture which comes with a String utc date in the form 2018-09-22T11:30:00Z
2) I then parse the date using SimpleDateFormat convertUtcDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); and convertUtcDate.setTimeZone(TimeZone.getTimeZone("GMT"));
3) I then get the current time using currentTime = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTime(); and compare the two using if(convertedDate.after(currentTime)) to find a team's next fixture. At this point I have found that a device will have these two dates in the same form, either with BST or GMT+01:00 but either way the two dates can be accurately compared.
4) I then format the date so it is in terms of a GMT offset using SimpleDateFormat convertToGmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US); and String dateString = convertToGmt.format(convertedDate);
5) For the utc date in 1) this returns Sat Sep 22 12:30:00 GMT+01:00 2018 regardless of the device. Notice that the time is different to the utc date. Not quite sure why this is the case (could be because the guy running the API is based in Germany which is an hour ahead of me here in England) but the important thing is that this time is correct (it refers to the Fulham - Watford game tomorrow which is indeed at 12:30 BST/GMT+01:00).
6) I then send this String along with a few other bits of information about the fixture to Firebase. It is important that the date be in the form GMT+01:00 rather than BST at this point because other devices may not recognise the BST form when they read that information.
7) When it comes to calling that information back from Firebase, I convert it back to a date by parsing it using SimpleDateFormat String2Date = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.US); and then I can arrange the fixtures in chronological order by comparing their dates.
I would just like to reiterate that this method works. I have checked for fixtures when the time zone in England changes back to GMT+00:00 and it still works fine. I have tried to make sure that everything is done in terms of GMT so that it would work anywhere. I cannot be sure though that this would be the case. Does anyone see any flaws in this method? Could it be improved?
Edit: Here is a snippet of the code which I hope simply and accurately represents what I am doing.
public class FragmentFixture extends Fragment {
SimpleDateFormat convertUtcDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
SimpleDateFormat String2Date = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.US);
SimpleDateFormat convertToGmt = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
private List<Fixture> fixtureList;
Date date1;
Date date2;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
convertUtcDate.setTimeZone(TimeZone.getTimeZone("GMT"));
fixtureList = new ArrayList<>();
// retrieve fixtures from API and get date for a certain fixture. I will provide an example
String date = "2018-09-22T11:30:00Z";
Date convertedDate = new Date();
try {
convertedDate = convertUtcDate.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
Date currentTime = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTime();
if (convertedDate.after(currentTime)) {
String dateString = convertToGmt.format(convertedDate);
Fixture fixture = new Fixture(dateString);
fixtureList.add(fixture);
Collections.sort(fixtureList, new DateSorter());
}
}
public class DateSorter implements Comparator<Fixture> {
#Override
public int compare(Fixture fixture, Fixture t1) {
try {
date1 = String2Date.parse(fixture.getDate());
} catch (ParseException e) {
e.printStackTrace();
}
try {
date2 = String2Date.parse(t1.getDate());
} catch (ParseException e) {
e.printStackTrace();
}
return date1.compareTo(date2);
}
}
public class Fixture {
public String date;
public Fixture() {
}
public Fixture(String date) {
this.date = date;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
}

Get the added/modified/taken date of the video from MediaStore

Where do I get the taken date of the video from MediaStore? I got the following fields from MediaStore.
MediaStore.Video.Media.DATE_MODIFIED
MediaStore.Video.Media.DATE_TAKEN
MediaStore.Video.Media.DATE_ADDED
Those fields returned seemly default values -
dateModified: 1477043336
dateTaken: 1477043336000
dateAdded: 1477043352
Formatted dates -
dateModified: 01/01/1970
dateTaken: 01/01/1970
dateAdded: 01/01/1970
I double checked the stock gallery > random video file and I do see the correct dates. I looked at the video columns in MediaStore and I didn't see any other columns which has correct dates.
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
String formattedDate = dateFormat.format(new Date(row.getColumnIndex(MediaStore.Video.Media.DATE_MODIFIED)));
String dateModified = dateFormat.format(new Date(row.getColumnIndex(MediaStore.Video.Media.DATE_MODIFIED)));
String dateTaken = dateFormat.format(new Date(row.getColumnIndex(MediaStore.Video.Media.DATE_TAKEN) * 1000L));
String dateAdded = dateFormat.format(new Date(row.getColumnIndex(MediaStore.Video.Media.DATE_ADDED) * 1000L));
Log.d(TAG, "dateModified: "+dateModified);
Log.d(TAG, "dateTaken: "+dateTaken);
Log.d(TAG, "dateAdded: "+dateAdded);
Log.d(TAG, "dateModified: "+row.getString(row.getColumnIndex(MediaStore.Video.Media.DATE_MODIFIED)));
Log.d(TAG, "dateTaken: "+row.getString(row.getColumnIndex(MediaStore.Video.Media.DATE_TAKEN)));
Log.d(TAG, "dateAdded: "+row.getString(row.getColumnIndex(MediaStore.Video.Media.DATE_ADDED)));
//Just multiply it by 1000 to get correct date
fun convertLongToDate(time: Long): String =
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
DateTimeFormatter.ofPattern("dd MMMM yyyy").format(
Instant.ofEpochMilli(time*1000)
.atZone(ZoneId.systemDefault())
.toLocalDate())
} else {
SimpleDateFormat("dd MMMM yyyy").format(
Date(time * 1000)
)
}
Looking at the annotations on the interface, DATE_ADDED and DATE_MODIFIED are annotated as SECONDS since the epoch, rather than milliseconds. DATE_TAKEN however is annotated as milliseconds since the epoch.
This difference in annotation explains the differences in zeroes that CommonsWare's answer notes. It also guides usage:
Since date formatters usually expect timestamps in millis, you should multiply second values by 1000 first.
Here is a simple function to get actual result of date format.
public String getDate(long val){
val*=1000L;
return new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new java.util.Date(val));
}
Those fields returned seemly default values
I do not know why your second one has three extra zeros at the end. But, using a Unix date converter site:
dateModified = 1477043336 = Fri, 21 Oct 2016 09:48:56 GMT
dateAdded = 1477043352 = Fri, 21 Oct 2016 09:49:12 GMT
And your dateTaken, without the zeros, is the same as dateModified. So, assuming you can figure out where your zeros came from (such as by randomly deciding to multiply the value by 1000L), you have valid timestamps.
Syntax for convert epoch to normal date in android as follows
long date=System.currentTimeMillis(); //current android time in epoch
Converts epoch to "dd/MM/yyyy HH:mm:ss" dateformat
Means 1477043336 = 21/10/2016 09:48:56
String NormalDate = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new java.util.Date(date));

ComparisonFailure with SimpleDateFormat on other machine

In an Android project I created the following functions to output a formatted date string:
static final String INPUT_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZ";
public static long getDateInMilliseconds(String text) {
Date date = getDate(text, INPUT_DATE_PATTERN);
return date == null ? 0 : date.getTime();
}
public static String getFormattedDate(long dateInMillisecons) {
Date date = new Date(dateInMillisecons);
DateFormat dateFormat = SimpleDateFormat.getDateTimeInstance(
SimpleDateFormat.FULL, SimpleDateFormat.SHORT);
return dateFormat.format(date);
}
private static Date getDate(String text, String pattern) {
SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.US);
Date date = null;
try {
date = dateFormat.parse(text);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
An example value of the text is:
"2016-04-02T09:00:00+02:00"
That means the time zone +02:00 complies with the RFC 822 time zone standard.
However, there is no way I can rely on the time zone in the string stays the same - it is served by a remote machine.
Here are two unit tests to check for the desired behavior.
#Test
public void getFormattedDateWithSummerTime() {
assertThat(DateFormatting.getFormattedDate(1459580400000L))
.isEqualTo("Saturday, April 2, 2016 9:00 AM");
}
#Test
public void getFormattedDateWithLeapYear() {
assertThat(DateFormatting.getFormattedDate(1456783200000L))
.isEqualTo("Monday, February 29, 2016 11:00 PM");
}
The tests pass on my machine. However, when I let the CI build run in the cloud they fail with the following error output:
org.junit.ComparisonFailure:
Expected :"Saturday, April 2, 2016 9:00 AM"
Actual :"Saturday, April 2, 2016 7:00 AM"
org.junit.ComparisonFailure:
Expected :"Monday, February 29, 2016 11:00 PM"
Actual :"Monday, February 29, 2016 10:00 PM"
The reason for failures is quite simple. If you use DateFormatting.getFormattedDate(1459580400000L)then you actually apply the system timezone (by just setting up a SimpleDateFormat-instance without any explicit timezone).
So you create a formatted string dependent on your system timezone and compare it to a hardwired fixed local representation string of the same time which might be right for your local timezone but not on another system.
Your JUnit-test is not universally applicable. Better compare global timestamps like "elapsed milliseconds since Unix epoch" than compare local representations.

How to find out GMT offset value in android

How to find out the values of GMT for user for example it is +05:30 for India.
How do calculate this +05:30 value in Android ?
I need this because I am using a java library in my app which has a function with this +05:30 field and I want to generate this field by calculation so that I wont have to fill up individual values for countries.
This is what works awesome
public double getOffset(){
TimeZone timezone = TimeZone.getDefault();
int seconds = timezone.getOffset(Calendar.ZONE_OFFSET)/1000;
double minutes = seconds/60;
double hours = minutes/60;
return hours;
}
First get the epoch system time
System.currentTimeMillis()
Then use a date object, set the time zone to GMT and initialize with the long valye
dateObj.setTimeZone(TimeZone.getTimeZone("GMT"))
To get time in GMT use below function where dateInString is the value of date,and format is date format as yyyyMMddHH
public static long getDate(String dateInString,String format){
long date = 0;
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
try {
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
Date d = dateFormat.parse(dateInString);
date = d.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
Use below method to get UTC :-
public int GetUnixTime()
{
Calendar calendar = Calendar.getInstance();
long now = calendar.getTimeInMillis();
int utc = (int)(now / 1000);
return (utc);
}
after you get UTC now compared it to the Epoch in this site http://www.xav.com/time.cgi.
see this below link :-
How can I get the current date and time in UTC or GMT in Java?
If you store a map between timezones and their GMT offsets in your app, you can call TimeZone.getDefault() to get the device's timezone and do a quick lookup to return the GMT offset. That way you don't have to rely on potentially tricky date/time calculations and can be sure you have the correct value.

How to conert local time to UTC time in android [duplicate]

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
When I create a new Date object, it is initialized to the current time but in the local timezone. How can I get the current date and time in GMT?
tl;dr
Instant.now() // Capture the current moment in UTC.
Generate a String to represent that value:
Instant.now().toString()
2016-09-13T23:30:52.123Z
Details
As the correct answer by Jon Skeet stated, a java.util.Date object has no time zone†. But its toString implementation applies the JVM’s default time zone when generating the String representation of that date-time value. Confusingly to the naïve programmer, a Date seems to have a time zone but does not.
The java.util.Date, j.u.Calendar, and java.text.SimpleDateFormat classes bundled with Java are notoriously troublesome. Avoid them. Instead, use either of these competent date-time libraries:
java.time.* package in Java 8
Joda-Time
java.time (Java 8)
Java 8 brings an excellent new java.time.* package to supplant the old java.util.Date/Calendar classes.
Getting current time in UTC/GMT is a simple one-liner…
Instant instant = Instant.now();
That Instant class is the basic building block in java.time, representing a moment on the timeline in UTC with a resolution of nanoseconds.
In Java 8, the current moment is captured with only up to milliseconds resolution. Java 9 brings a fresh implementation of Clock captures the current moment in up to the full nanosecond capability of this class, depending on the ability of your host computer’s clock hardware.
It’s toString method generates a String representation of its value using one specific ISO 8601 format. That format outputs zero, three, six or nine digits digits (milliseconds, microseconds, or nanoseconds) as necessary to represent the fraction-of-second.
If you want more flexible formatting, or other additional features, then apply an offset-from-UTC of zero, for UTC itself (ZoneOffset.UTC constant) to get a OffsetDateTime.
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
Dump to console…
System.out.println( "now.toString(): " + now );
When run…
now.toString(): 2014-01-21T23:42:03.522Z
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.
Joda-Time
UPDATE: The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
Using the Joda-Time 3rd-party open-source free-of-cost library, you can get the current date-time in just one line of code.
Joda-Time inspired the new java.time.* classes in Java 8, but has a different architecture. You may use Joda-Time in older versions of Java. Joda-Time continues to work in Java 8 and continues to be actively maintained (as of 2014). However, the Joda-Time team does advise migration to java.time.
System.out.println( "UTC/GMT date-time in ISO 8601 format: " + new org.joda.time.DateTime( org.joda.time.DateTimeZone.UTC ) );
More detailed example code (Joda-Time 2.3)…
org.joda.time.DateTime now = new org.joda.time.DateTime(); // Default time zone.
org.joda.time.DateTime zulu = now.toDateTime( org.joda.time.DateTimeZone.UTC );
Dump to console…
System.out.println( "Local time in ISO 8601 format: " + now );
System.out.println( "Same moment in UTC (Zulu): " + zulu );
When run…
Local time in ISO 8601 format: 2014-01-21T15:34:29.933-08:00
Same moment in UTC (Zulu): 2014-01-21T23:34:29.933Z
For more example code doing time zone work, see my answer to a similar question.
Time Zone
I recommend you always specify a time zone rather than relying implicitly on the JVM’s current default time zone (which can change at any moment!). Such reliance seems to be a common cause of confusion and bugs in date-time work.
When calling now() pass the desired/expected time zone to be assigned. Use the DateTimeZone class.
DateTimeZone zoneMontréal = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( zoneMontréal );
That class holds a constant for UTC time zone.
DateTime now = DateTime.now( DateTimeZone.UTC );
If you truly want to use the JVM’s current default time zone, make an explicit call so your code is self-documenting.
DateTimeZone zoneDefault = DateTimeZone.getDefault();
ISO 8601
Read about ISO 8601 formats. Both java.time and Joda-Time use that standard’s sensible formats as their defaults for both parsing and generating strings.
† Actually, java.util.Date does have a time zone, buried deep under layers of source code. For most practical purposes, that time zone is ignored. So, as shorthand, we say java.util.Date has no time zone. Furthermore, that buried time zone is not the one used by Date’s toString method; that method uses the JVM’s current default time zone. All the more reason to avoid this confusing class and stick with Joda-Time and java.time.
java.util.Date has no specific time zone, although its value is most commonly thought of in relation to UTC. What makes you think it's in local time?
To be precise: the value within a java.util.Date is the number of milliseconds since the Unix epoch, which occurred at midnight January 1st 1970, UTC. The same epoch could also be described in other time zones, but the traditional description is in terms of UTC. As it's a number of milliseconds since a fixed epoch, the value within java.util.Date is the same around the world at any particular instant, regardless of local time zone.
I suspect the problem is that you're displaying it via an instance of Calendar which uses the local timezone, or possibly using Date.toString() which also uses the local timezone, or a SimpleDateFormat instance, which, by default, also uses local timezone.
If this isn't the problem, please post some sample code.
I would, however, recommend that you use Joda-Time anyway, which offers a much clearer API.
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
//Local time zone
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
//Time in GMT
return dateFormatLocal.parse( dateFormatGmt.format(new Date()) );
This definitely returns UTC time: as String and Date objects !
static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static Date getUTCdatetimeAsDate() {
// note: doesn't check for null
return stringDateToDate(getUTCdatetimeAsString());
}
public static String getUTCdatetimeAsString() {
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
final String utcTime = sdf.format(new Date());
return utcTime;
}
public static Date stringDateToDate(String StrDate) {
Date dateToReturn = null;
SimpleDateFormat dateFormat = new SimpleDateFormat(DATEFORMAT);
try {
dateToReturn = (Date)dateFormat.parse(StrDate);
}
catch (ParseException e) {
e.printStackTrace();
}
return dateToReturn;
}
Calendar c = Calendar.getInstance();
System.out.println("current: "+c.getTime());
TimeZone z = c.getTimeZone();
int offset = z.getRawOffset();
if(z.inDaylightTime(new Date())){
offset = offset + z.getDSTSavings();
}
int offsetHrs = offset / 1000 / 60 / 60;
int offsetMins = offset / 1000 / 60 % 60;
System.out.println("offset: " + offsetHrs);
System.out.println("offset: " + offsetMins);
c.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
c.add(Calendar.MINUTE, (-offsetMins));
System.out.println("GMT Time: "+c.getTime());
Actually not time, but it's representation could be changed.
SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(f.format(new Date()));
Time is the same in any point of the Earth, but our perception of time could be different depending on location.
This works for getting UTC milliseconds in Android.
Calendar c = Calendar.getInstance();
int utcOffset = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET);
Long utcMilliseconds = c.getTimeInMillis() + utcOffset;
Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Then all operations performed using the aGMTCalendar object will be done with the GMT time zone and will not have the daylight savings time or fixed offsets applied
Wrong!
Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
aGMTCalendar.getTime(); //or getTimeInMillis()
and
Calendar aNotGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));aNotGMTCalendar.getTime();
will return the same time. Idem for
new Date(); //it's not GMT.
This code prints the current time UTC.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Test
{
public static void main(final String[] args) throws ParseException
{
final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(f.format(new Date()));
}
}
Result
2013-10-26 14:37:48 UTC
Here is what seems to be incorrect in Jon Skeet's answer. He said:
java.util.Date is always in UTC. What makes you think it's in local
time? I suspect the problem is that you're displaying it via an
instance of Calendar which uses the local timezone, or possibly using
Date.toString() which also uses the local timezone.
However, the code:
System.out.println(new java.util.Date().getHours() + " hours");
gives the local hours, not GMT (UTC hours), using no Calendar and no SimpleDateFormat at all.
That is why is seems something is incorrect.
Putting together the responses, the code:
System.out.println(Calendar.getInstance(TimeZone.getTimeZone("GMT"))
.get(Calendar.HOUR_OF_DAY) + " Hours");
shows the GMT hours instead of the local hours -- note that getTime.getHours() is missing because that would create a Date() object, which theoretically stores the date in GMT, but gives back the hours in the local time zone.
If you want a Date object with fields adjusted for UTC you can do it like this with Joda Time:
import org.joda.time.DateTimeZone;
import java.util.Date;
...
Date local = new Date();
System.out.println("Local: " + local);
DateTimeZone zone = DateTimeZone.getDefault();
long utc = zone.convertLocalToUTC(local.getTime(), false);
System.out.println("UTC: " + new Date(utc));
You can use:
Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Then all operations performed using the aGMTCalendar object will be done with the GMT time zone and will not have the daylight savings time or fixed offsets applied. I think the previous poster is correct that the Date() object always returns a GMT it's not until you go to do something with the date object that it gets converted to the local time zone.
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(date));
Here is my implementation of toUTC:
public static Date toUTC(Date date){
long datems = date.getTime();
long timezoneoffset = TimeZone.getDefault().getOffset(datems);
datems -= timezoneoffset;
return new Date(datems);
}
There's probably several ways to improve it, but it works for me.
You can directly use this
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(new Date())+"");
Here an other suggestion to get a GMT Timestamp object:
import java.sql.Timestamp;
import java.util.Calendar;
...
private static Timestamp getGMT() {
Calendar cal = Calendar.getInstance();
return new Timestamp(cal.getTimeInMillis()
-cal.get(Calendar.ZONE_OFFSET)
-cal.get(Calendar.DST_OFFSET));
}
Here is another way to get GMT time in String format
String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z" ;
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String dateTimeString = sdf.format(new Date());
With:
Calendar cal = Calendar.getInstance();
Then cal have the current date and time.
You also could get the current Date and Time for timezone with:
Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));
You could ask cal.get(Calendar.DATE); or other Calendar constant about others details.
Date and Timestamp are deprecated in Java. Calendar class it isn't.
Sample code to render system time in a specific time zone and a specific format.
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class TimZoneTest {
public static void main (String[] args){
//<GMT><+/-><hour>:<minutes>
// Any screw up in this format, timezone defaults to GMT QUIETLY. So test your format a few times.
System.out.println(my_time_in("GMT-5:00", "MM/dd/yyyy HH:mm:ss") );
System.out.println(my_time_in("GMT+5:30", "'at' HH:mm a z 'on' MM/dd/yyyy"));
System.out.println("---------------------------------------------");
// Alternate format
System.out.println(my_time_in("America/Los_Angeles", "'at' HH:mm a z 'on' MM/dd/yyyy") );
System.out.println(my_time_in("America/Buenos_Aires", "'at' HH:mm a z 'on' MM/dd/yyyy") );
}
public static String my_time_in(String target_time_zone, String format){
TimeZone tz = TimeZone.getTimeZone(target_time_zone);
Date date = Calendar.getInstance().getTime();
SimpleDateFormat date_format_gmt = new SimpleDateFormat(format);
date_format_gmt.setTimeZone(tz);
return date_format_gmt.format(date);
}
}
Output
10/08/2011 21:07:21
at 07:37 AM GMT+05:30 on 10/09/2011
at 19:07 PM PDT on 10/08/2011
at 23:07 PM ART on 10/08/2011
Just to make this simpler, to create a Date in UTC you can use Calendar :
Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Which will construct a new instance for Calendar using the "UTC" TimeZone.
If you need a Date object from that calendar you could just use getTime().
Converting Current DateTime in UTC:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
DateTimeZone dateTimeZone = DateTimeZone.getDefault(); //Default Time Zone
DateTime currDateTime = new DateTime(); //Current DateTime
long utcTime = dateTimeZone.convertLocalToUTC(currDateTime .getMillis(), false);
String currTime = formatter.print(utcTime); //UTC time converted to string from long in format of formatter
currDateTime = formatter.parseDateTime(currTime); //Converted to DateTime in UTC
public static void main(String args[]){
LocalDate date=LocalDate.now();
System.out.println("Current date = "+date);
}
This worked for me, returns the timestamp in GMT!
Date currDate;
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
long currTime = 0;
try {
currDate = dateFormatLocal.parse( dateFormatGmt.format(new Date()) );
currTime = currDate.getTime();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The Simple Function that you can use:
Edit: this version uses the modern java.time classes.
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("dd-MM-uuuu HH:mm:ss z");
public static String getUtcDateTime() {
return ZonedDateTime.now(ZoneId.of("Etc/UTC")).format(FORMATTER);
}
Return value from the method:
26-03-2022 17:38:55 UTC
Original function:
public String getUTC_DateTime() {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss z");
dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));//gmt
return dateTimeFormat.format(new Date());
}
return of above function:
26-03-2022 08:07:21 UTC
To put it simple. A calendar object stores information about time zone but when you perform cal.getTime() then the timezone information will be lost. So for Timezone conversions I will advice to use DateFormat classes...
this is my implementation:
public static String GetCurrentTimeStamp()
{
Calendar cal=Calendar.getInstance();
long offset = cal.getTimeZone().getOffset(System.currentTimeMillis());//if you want in UTC else remove it .
return new java.sql.Timestamp(System.currentTimeMillis()+offset).toString();
}
Use this Class to get ever the right UTC Time from a Online NTP Server:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
class NTP_UTC_Time
{
private static final String TAG = "SntpClient";
private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;
private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;
// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;
private long mNtpTime;
public boolean requestTime(String host, int timeout) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
socket.close();
mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
} catch (Exception e) {
// if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
return false;
}
return true;
}
public long getNtpTime() {
return mNtpTime;
}
/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset+1];
byte b2 = buffer[offset+2];
byte b3 = buffer[offset+3];
// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);
return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
}
/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
}
/**
* Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
*/
private void writeTimeStamp(byte[] buffer, int offset) {
int ofs = offset++;
for (int i=ofs;i<(ofs+8);i++)
buffer[i] = (byte)(0);
}
}
And use it with:
long now = 0;
NTP_UTC_Time client = new NTP_UTC_Time();
if (client.requestTime("pool.ntp.org", 2000)) {
now = client.getNtpTime();
}
If you need UTC Time "now" as DateTimeString use function:
private String get_UTC_Datetime_from_timestamp(long timeStamp){
try{
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
int tzt = tz.getOffset(System.currentTimeMillis());
timeStamp -= tzt;
// DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.getDefault());
DateFormat sdf = new SimpleDateFormat();
Date netDate = (new Date(timeStamp));
return sdf.format(netDate);
}
catch(Exception ex){
return "";
}
}
and use it with:
String UTC_DateTime = get_UTC_Datetime_from_timestamp(now);
If you want to avoid parsing the date and just want a timestamp in GMT, you could use:
final Date gmt = new Timestamp(System.currentTimeMillis()
- Calendar.getInstance().getTimeZone()
.getOffset(System.currentTimeMillis()));
public class CurrentUtcDate
{
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC Time is: " + dateFormat.format(date));
}
}
Output:
UTC Time is: 22-01-2018 13:14:35
You can change the date format as needed.
Current date in the UTC
Instant.now().toString().replaceAll("T.*", "");

Categories

Resources