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.
Related
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;
}
}
}
I'm always getting the parse exception even if the format to check and the string value are same.
Here is the code:
String format = "EEE MMM dd HH:mm:ss z yyyy";
String value = "Mon Sep 18 10:30:06 MST 2017";
public static boolean isValidFormat(String format, String value) {
Date date = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat(format);
date = sdf.parse(value); // here it breaks
if (!value.equals(sdf.format(date))) {
date = null;
}
} catch (ParseException ex) {
ex.printStackTrace(); //java.text.ParseException: Unparseable date:
"Mon Sep 18 10:30:06 MST 2017" (at offset 0)
}
return date != null;
}
It says that your date-time string is unparseable at index 0. Index 0 is where it says Mon, so the three letter time zone abbreviation is not the first suspect. The locale is. “Mon” works as abbreviation for Monday in English, but not in very many other languages. So if your device has a non-English language setting — maybe it has even been changed recently — this will fully explain your observation.
The shortsighted solution is
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.ROOT);
I use Locale.ROOT to mean that no language specific processing should be done. If your string is in English because English is generally the language used in computing around the globe, I would consider this choice appropriate. If on the other hand it is in English because it comes from an English speaking locale, that locale will be the right one to use.
With this change, on my computer your code formats your date into Mon Sep 18 11:30:06 MDT 2017, which, as you can see is not the same as the value we started out from, so your method returns false. My JVM understood MST as Mountain Standard Time, and then assumed summer time (DST) in September and formatted the string accordingly.
ThreeTenABP
That said, Date and SimpleDateFormat are long outdated classes. You should give it a thought to get rid of them and use the modern Java date and time API instead. On Android you get it in the ThreeTenABP, see this question: How to use ThreeTenABP in Android Project. Now you may do:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format, Locale.ROOT);
try {
return ZonedDateTime.parse(value, dtf).format(dtf).equals(value);
} catch (DateTimeParseException dtpe) {
dtpe.printStackTrace();
return false;
}
This behaves the same as above.
Three letter time zone abbreviations
You should avoid the three and four letter time zone abbreviations where you can. They are not standardized and generally ambiguous. MST, for example, may mean Malaysia Standard Time or Mountain Standard Time. The latter isn’t even a full time zone, since MDT is used for the greater part of the year, which caused the trouble I observed as I said above.
Instead, see if you can get a string in ISO 8601 format, like 2017-09-18T10:30:06+08:00. Second best, just get something unambiguous. One way is to include an offset from UTC rather than a time zone ID (or both).
Never use SimpleDateFormat or DateTimeFormatter without a Locale
Since the given date-time is in English, you should use Locale.ENGLISH with your date-time parser; otherwise the parsing will fail in a system (computer, phone etc.) which is using a non-English type of locale.
Also, note that the date-time API of java.util 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.
Demo:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Mon Sep 18 10:30:06 MST 2017";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
}
}
Output:
2017-09-18T10:30:06-06:00[America/Denver]
An important note about timezone before we proceed further:
Avoid specifying a timezone with the 3-letter abbreviation. A timezone should be specified with a name in the format, Region/City e.g. ZoneId.of("Europe/London"). With this convention, the ZoneId for UTC can be specified with ZoneId.of("Etc/UTC"). A timezone specified in terms of UTC[+/-]Offset can be specified as Etc/GMT[+/-]Offset e.g. ZoneId.of("Etc/GMT+1"), ZoneId.of("Etc/GMT+1") etc.
There are some exceptional cases as well e.g. to specify the timezone of Turkey, we use
ZoneId.of("Turkey")
The following code will give you all the available ZoneIds:
// Get the set of all time zone IDs.
Set<String> allZones = ZoneId.getAvailableZoneIds();
You should ask your server application to provide you with the date-time using this convention e.g.
Mon Sep 18 10:30:06 America/Denver 2017
The above code, without any change, will work for this date-time string.
Coming back to the original topic:
By default, DateTimeFormatter#ofPattern uses the default FORMAT locale which the JVM sets during startup based on the host environment. Same is the case with SimpleDateFormat. I have tried to illustrate the problem through the following demo:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
final String strDateTime = "Mon Sep 18 10:30:06 America/Denver 2017";
DateTimeFormatter dtfWithDefaultLocale = null;
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out
.println("Parsed with JVM's default locale: " + ZonedDateTime.parse(strDateTime, dtfWithDefaultLocale));
// Setting the JVM's default locale to Locale.FRANCE
Locale.setDefault(Locale.FRANCE);
// Using DateTimeFormatter with Locale.ENGLISH explicitly (recommended)
DateTimeFormatter dtfWithEnglishLocale = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu", Locale.ENGLISH);
System.out.println("JVM's Locale: " + Locale.getDefault());
System.out.println("DateTimeFormatter's Locale: " + dtfWithEnglishLocale.getLocale());
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtfWithEnglishLocale);
System.out.println("Parsed with Locale.ENGLISH: " + zdt);
System.out.println("JVM's Locale: " + Locale.getDefault());
// Using DateTimeFormatter with the default Locale
dtfWithDefaultLocale = DateTimeFormatter.ofPattern("EEE MMM d H:m:s z uuuu");
System.out.println("DateTimeFormatter's Locale: " + dtfWithDefaultLocale.getLocale());
System.out
.println("Parsed with JVM's default locale: " + ZonedDateTime.parse(strDateTime, dtfWithDefaultLocale));
}
}
Output:
JVM's Locale: en_GB
DateTimeFormatter's Locale: en_GB
Parsed with JVM's default locale: 2017-09-18T10:30:06-06:00[America/Denver]
JVM's Locale: fr_FR
DateTimeFormatter's Locale: en
Parsed with Locale.ENGLISH: 2017-09-18T10:30:06-06:00[America/Denver]
JVM's Locale: fr_FR
DateTimeFormatter's Locale: fr_FR
Exception in thread "main" java.time.format.DateTimeParseException: Text 'Mon Sep 18 10:30:06 America/Denver 2017' could not be parsed at index 0
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)
at java.base/java.time.ZonedDateTime.parse(ZonedDateTime.java:598)
at Main.main(Main.java:32)
The following demo, using SimpleDateFormat, is just for the sake of completeness:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
final String strDateTime = "Mon Sep 18 10:30:06 MST 2017";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM d H:m:s z yyyy", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
System.out.println(date);
}
}
Output:
Mon Sep 18 18:30:06 BST 2017
Note: The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the milliseconds from the Epoch of January 1, 1970. When you print an object of java.util.Date, its toString method returns the date-time calculated from this milliseconds value. Since java.util.Date does not have timezone information, it applies the timezone of your JVM and displays the same. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFomrat and obtain the formatted string from it.
Here is the code of dateformatter which will hep you to convert your date into any time format.
public void setDate(String date) {
dateInput = (TextView) itemView.findViewById(R.id.dateText);
DateFormat inputFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
try {
dateData = inputFormat.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
DateFormat outputFormat = new SimpleDateFormat("pur your desirable format");
String outputString = outputFormat.format(dateData);
dateInput.setText(outputString);
}
I use the almost use the same code as you do with only slight difference in SimpleDateFormat instantiation.
public static final String DATE_FORMAT = "EEE MMM d yyyy z HH:mm:ss";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.ROOT);
simpleDateFormat.format(date);
It returns Mon Sep 18 2017 GMT+03:00 23:04:10.
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.
I want convert data like 2016-4-10 00:00:00 to timestamp.
I use this code (I send this date as argument to this method):
public static long parseUTimeAndGiveTimestamp(String time) {
if (time != null && !time.equals("")) {
long longTime = 0;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS");
Date date;
try {
time += ".000";
date = sdf.parse(time);
} catch (Exception e) {
e.printStackTrace();
return longTime;
}
longTime = date.getTime();
return longTime / 1000;
}
return 0;
}
But I get 1460235600 value and if I convert it to date again I get:
Sat, 09 Apr 2016 21:00:00
(before 10.04 - after 09.04)
So you can help me?
There is no issue with your code. There is some issue with the timezones. Your SimpleDateFormat will be using your local timezone. You probable might be getting the timestamp for your locale and while converting it back to the date, you are checking in GMT timezone. To test this just add
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
before parsing the date.
So basically you are not using the same timezones to convert date to timestamp and while converting timestamp to zone.
try to use one M to parse single-digit month format. It also handles two-digits correctly...
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-dd kk:mm:ss.SSS");
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.