JodaTime confused about TimeZone offset - android

I receive a Date String like "2018-06-21T13:30:00Z"
I parse it with the pattern "yyyy-MM-dd'T'HH:mm:ssZ"
I am in GMT+2 and the result looks like 2018-06-21T15:30:00.000+02:00
while i expected it to look like this 2018-06-21T13:30:00.000+02:00
Is the offset supposed to be already applied in the HH:mm:ss part of the Result?
Code
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ").parseDateTime("2018-06-21T13:30:00Z")
joda:2.9.7

Yes the date time given is in the local time of +02:00.
From ISO 8601 Wikipedia Time offsets from UTC:
The following times all refer to the same moment: "18:30Z", "22:30+04", "1130−0700", and "15:00−03:30". Nautical time zone letters are not used with the exception of Z. To calculate UTC time one has to subtract the offset from the local time, e.g. for "15:00−03:30" do 15:00 − (−03:30) to get 18:30 UTC.
So for your case: 2018-06-21T15:30:00.000+02:00 means 15:30 - 02:00 so a UTC of 13:30

Related

Joda Time hour interval

I get time from server in format { "from" : "12-00", "to" : "01-00" }
Then, I parse it like this
DateTimeFormat.forPattern("HH:mm").parseDateTime(dateString)
Then, I need to check if current time is in this hour range:
Interval(from, to).containsNow()
Interval constructor throws error because second date more than first
DateTime object time is 1970-01-01T12:00:00.000Z and 1970-01-01T01:00:00.000Z
How can I check if current hour is in hour range? Is there any hour range in Joda?
Since you are using 24-hour format, you need to use the date as well. You are currently comparing 12:00 of 01-01-1970 (the Unix start Date) with 01:00 of the same day, and 12:00 is after 1:00 and that is an invalid interval.
Change the DateTime pattern to "MM/dd/yyyy HH:mm" or something else that works for you and contains both the date and the time that suits your needs. Then, you can make the check.

Showing correct time from Milliseconds with desired TimeZone

I'm developing an application which takes data from Google TimeZone API.
Simply I have time in milliseconds of desired place on Earth.
For Example : 1504760156000 it's showing Date time In London which is
Thu Sep 07 2017 09:55:56
As I'm in TimeZone +05:00 from UTC if I manipulate 1504760156000 these milliseconds it will show me whole date time like below:
Thu Sep 07 2017 09:55:56 GMT+0500 (Pakistan Standard Time)
but I want to show:
Thu Sep 07 2017 09:55:56 GMT+0100 (British Summer Time)
The problem is: I have correct date and time for London but enable to show/change TimeZone without changing Time because Time is correct according to London.
UPDATED
After getting some comments. You are not getting me here in my example.
Suppose I am in Pakistan and Time here is 1:55 PM so I asked GOOGLE API via my application to tell me whats the time in London at moment. Google API tell me time in London is 1504760156000 (9:55 AM) in milliseconds if I convert these milliseconds to Date Object it will print out like below:
Date date =new Date(1504760156000)
Thu Sep 07 2017 09:55:56 GMT+0500 (Pakistan Standard Time)
It will manipulate it according to my Local TimeZone but I want results like below
Thu Sep 07 2017 09:55:56 GMT+0100 (British Summer Time)
Updated 2
I prepared timestamp in seconds in UTC as Google Time Zone API needed timestamp UTC in form of seconds
"https://maps.googleapis.com/maps/api/timezone/json?location="+Latitude +","+Longitude+"&timestamp="+currentTimeUTCinSeonds+"&key="API KEY"
Google API respond me with below JSON against London.
{
"dstOffset" : 3600,
"rawOffset" : 0,
"status" : "OK",
"timeZoneId" : "Europe/London",
"timeZoneName" : "British Summer Time"
}
According to Docs:
Calculating the Local Time
The local time of a given location is the sum of the timestamp
parameter, and the dstOffset and rawOffset fields from the result.
I Sum up result timestamp+rawoffset+dstoffset*1000='1504760156000' (at moment when I tried it)
Code from Project
Long ultimateTime=((Long.parseLong(timeObject1.getDstOffset())*1000)+(Long.parseLong(timeObject1.getRawOffset())*1000)+timestamp*1000);
timeObject1.setTimestamp(ultimateTime); //its Sime POJO object to save current time of queried Location
Date date=new Date(ultimateTime);
date1.setText("Date Time : "+date);
As I said I'm manipulating result in Local Time Zone so it gave me below result at that time:
Thu Sep 07 2017 09:55:56 GMT+0500 (Pakistan Standard Time)
But I knew API gave me correct time. The problem is Local offset from UTC . I just want to change GMT+0500 to GMT+0100
Timestamps represent an "absolute" value of a time elapsed since epoch. Your currentTimeUTCinSeconds, for example, represent the number of seconds since unix epoch (which is 1970-01-01T00:00Z, or January 1st 1970 at midnight in UTC). Java API's usually work with the number of milliseconds since epoch.
But the concept is the same - those values are "absolute": they are the same for everyone in the world, no matter where they are. If 2 people in different parts of the world (in different timezones) get the current timestamp at the same time, they'll all get the same number.
What changes is that, in different timezones, this same number represents a different local date and time.
For example, the timestamp you're using, that corresponds to Sep 7th 2017 08:55:56 UTC, which value is 1504774556 (the number of seconds since epoch). This same number corresponds to 09:55 in London, 13:55 in Karachi, 17:55 in Tokyo and so on. Changing this number will change the local times for everyone - there's no need to manipulate it.
If you want to get a java.util.Date that represents this instant, just do:
int currentTimeUTCinSeconds = 1504774556;
// cast to long to not lose precision
Date date = new Date((long) currentTimeUTCinSeconds * 1000);
This date will keep the value 1504774556000 (the number of milliseconds since epoch). This value corresponds to 09:55 in London, 13:55 in Karachi and 17:55 in Tokyo.
But printing this date will convert it to your JVM default timezone (here is a good explanation about the behaviour of Date::toString() method). When you do "Date Time : "+date, it implicity calls toString() method, and the result is the date converted to your default timezone.
If you want the date in a specific format and in a specific timezone, you'll need a SimpleDateFormat. Just printing the date (with System.out.println or by logging it) won't work: you can't change the format of the date object itself, because a Date has no format.
I also use a java.util.Locale to specify that the month and day of week must be in English. If you don't specify a locale, it'll use the system default, and it's not guaranteed to always be English (and this can be changed, even at runtime, so it's better to always specify a locale):
// use the same format, use English for month and day of week
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (zzzz)", Locale.ENGLISH);
// set the timezone I want
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
// format the date
System.out.println(sdf.format(date));
The output will be:
Thu Sep 07 2017 09:55:56 GMT+0100 (British Summer Time)
Note that I don't need to manipulate the timestamp value. I don't use the google API, but I think their explanation is too confusing and the code above achieve the same results with less complication.
In your specific case, you can do:
date1.setText("Date Time : "+sdf.format(date));
Java new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. To make it work, you'll also need the ThreeTenABP (more on how to use it here).
To get a date from a timestamp, I use a org.threeten.bp.Instant with a org.threeten.bp.ZoneId to convert it to a timezone, creating a org.threeten.bp.ZonedDateTime. Then I use a org.threeten.bp.format.DateTimeFormatter to format it:
int currentTimeUTCinSeconds = 1504774556;
// get the date in London from the timestamp
ZonedDateTime z = Instant.ofEpochSecond(currentTimeUTCinSeconds).atZone(ZoneId.of("Europe/London"));
// format it
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss 'GMT'XX (zzzz)", Locale.ENGLISH);
System.out.println(fmt.format(z));
The output is the same:
Thu Sep 07 2017 09:55:56 GMT+0100 (British Summer Time)
In your case, just do:
date1.setText("Date Time : "+fmt.format(z));

Android Joda Time - How to Load UTC from File

I am using Joda Time. I want to compare 2 dates/times A and B to determine if B has exceeded A.
Problem - When I logcat A it's not in UTC. When I logcat B it's in UTC. Therefore the comparison is not real.
A - A UTC time loaded from a file
B -The "System Time" in UTC
Code:
A - DateTime csvTime = new DateTime( inArray[5] ) ; //inArray[x] is loaded from a file and has this format: 2017-02-10T01:09:00Z
B - new DateTime(DateTimeZone.UTC)
Question - How do I load inArray[5] so it is truly in UTC and compares with B accurately?
Thanks in advance and yes I have looked at 100s of posts on this. I have yet to find a post that tells me the syntax for A above, how to store an external ISO 8601 format date in UTC internal. I have played around with TimeZone set default to force Joda/JVMP default TZ but that then puts me in a position of having to specify the TimeZone which I do not want to do.
If your input is already in UTC (trailing "Z") then I suggest you to parse it this way:
DateTime dt =
ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed().parseDateTime(
"2017-02-10T01:09:00Z"
);
System.out.println(dt); // 2017-02-10T01:09:00.000Z
Otherwise you could tranform your A-DateTime to UTC by withZone(DateTimeZone.UTC).

Date difference is showing negative value in android

In sqlite date difference is coming negative.
SELECT (strftime('%s','now') - strftime('%s', msl_last_sync_date_time))/60/60 as last_synch_time
FROM mobi_sync_log
WHERE my msl_last_sync_date_time is 2015-06-24 10:36:27
Please suggest some idea.
now returns a time in UTC. 2015-06-24 10:36:27 is in the future in UTC considering when you posted the question.
Consider storing all your datetimes in UTC, or add an explicit timezone such as 2015-06-24 10:36:27 +05:30 to them.

Custom the display value of SimpleDateFormat in android

I currently work on a double value that represent the total consumed time
for example, I have a 260 that means 260 second is consumed
To display to user, I would like to format it
for example , it should be something like 0year,0month,0day,1hr,2min,30sec
But I found the SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); is not quite suit my case (seems the "h" in "hr" is conflicted with the hour symbol?)
So , how to change the HH:mm:ss to the case mentioned above?
Thanks for helping
DateFormat is useful to format dates, not an absolute value of time.
To achieve your goal, you can take a look to Formatter
Hope this sample helps you:
String total_consumed_time = String.format("%01d year, %01d month, %01d day, %01d hr, %01d min, %01d sec", time_year, time_month, time_day, time_hour, time_min, time_seg);
I didn't try that code, but I use similar workaround with an absolute time in milliseconds:
long time = 260000; // time in mseg
long time_hour = TimeUnit.MILLISECONDS.toHours(time);
time -= TimeUnit.HOURS.toMillis(time_hour);
long time_min = TimeUnit.MILLISECONDS.toMinutes(time);
time -= TimeUnit.MINUTES.toMillis(time_min);
long time_seg = TimeUnit.MILLISECONDS.toSeconds(time);
String total_time = String.format("%02d:%02d:%02d", time_hour, time_min, time_seg);
With a result of "00:04:20" (4 minutes and 20 seconds).
Accepted answer is in most cases okay for solving your problem, but gives wrong reason why not to use the class SimpleDateFormat. This format class is well suited for objects of type java.util.Date (which are kind of unix timestamps in milliseconds hence absolute value of time, NOT dates). In order to treat letters like "hr" as literals you need to escape them. Example code:
// create timestamp
java.util.Date jud = new java.util.Date(260 * 1000); // milliseconds
// create format for timestamp
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy'year',M'month',d'day',H'hr',m'min',s'sec'");
// otherwise you will get extra offset time (example: in England +1 hour DST)
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
// output: 1970year,1month,1day,0hr,4min,20sec
String formatted = sdf.format(jud);
System.out.println(formatted);
Even with the applied and tricky time zone correction in code you face the problem that you have an output for the year 1970, a point in time. Hereby you can see that SimpleDateFormat does format timestamps well (absolute values in time) but NOT durations (amount resp. length of time). This semantic problem can also not be solved by the approach to use java.util.Formatter as soon as the input increases the day limit of 86400 seconds.
Old JDK and Android don't offer a built-in solution for evaluating time differences expressed in years, months and days. Java 8 does offer (limited) support with new API (class 'Period' only for date part, not time part). External libraries like JodaTime or my own one (actually only as alpha-version) give more support. JodaTime even offers a special PeriodFormatter which is ideal for solving your problem.

Categories

Resources