I'm doing the following call in my Android app:
DateUtils.getRelativeDateTimeString(
context,
myTime,
DateUtils.MINUTE_IN_MILLIS,
DateUtils.WEEK_IN_MILLIS,
0)
This returns strings like
3 hours ago, 5:58 PM
Yesterday, 2:23 PM
2 days ago, 9:02 AM
I only want to show the first part of this, the time is not interesting, especially not for a time which is 2 days in the past, or even weeks.
The last argument of this function is the flags argument. And there is the flag FORMAT_SHOW_TIME, but it seems that this flag is always enabled and disabling is not possible, or am I missing something?
What options do I have besides splitting the string by ',', which will for sure trigger other problems on some locales
You can use getRelativeTimeSpanString instead. It prints without absolute time. It does not support transitionResolution feature, though.
DateUtils.getRelativeTimeSpanString(
myTime,
now,
DateUtils.MINUTE_IN_MILLIS,
)
Here is a javadoc comment of RelativeDateTimeFormatter.getRelativeDateTimeString which is used by DateUtils.getRelativeDateTimeString
The function is similar to getRelativeTimeSpanString, but it always appends the absolute time to the relative time string to return '[relative time/date clause], [absolute time clause]
Related post: Format relative date to human readable format in Android using Android DateUtils API
Related
I wanted to get the TimeInMillis value for alternate dates for the next 30 days from any selected date. I tried to get value for the dates using a for loop. But the code always returns the last 3 dates as wrong. Is there any alternate better way to get what i'm doing?
fun calculateDates(startDate: Long) {
val singeDateDifference = 86400000
val cancelledDates = arrayListOf<Long>()
for (i in 2..30 step 2) {
val difference = i * singeDateDifference
cancelledDates.add(startDate + difference)
}
}
The answer i'm getting for the above is this. I have logged the Long value as dates for better understanding.
startDate: 01/01/2022
[02/01/2022, 04/01/2022, 06/01/2022, 08/01/2022, 10/01/2022, 12/01/2022, 14/01/2022, 16/01/2022, 18/01/2022, 20/01/2022, 22/01/2022, 24/01/2022, 07/12/2021, 09/12/2021, 11/12/2021]
I'm always getting the last 3 dates from previous month. I can't figure out what is wrong with the code.
In the line
val difference = i * singeDateDifference
you are using integer types (Int in Kotlin), so for large enough results of your multiplication you will get an integer overflow (because Int.MAX_VALUE is 2147483647), which means that the result of the multiplication will be a negative value.
That happens for the last 3 difference values, which causes the last 3 dates to be 1 month behind.
Just ensure that the multiplication is done with Long types, one simple way to do that would be to set the date difference factor to Long.
// ensure we use Long when calculating with epoch millis
val singeDateDifference = 86400000L
This will cause the multiplication to be performed with the Long values and the result will also be a Long value.
That will fix the bug and print the dates as you would expect.
In general cases time, dates and calendars are not easy to get right and years of work have been put into APIs such as the Time API.
When working with times and dates, my suggestion would be, to use the Time API classes and methods instead. They are in the package java.time (java.time.*).
The documentation is here: https://developer.android.com/reference/java/time/package-summary
That will prevent bugs like the one you had, because it allows you to work with higher-level concepts, such as .plusHours(24) or .plusDays(1) (which is not the same in all cases!) instead of doing all the calculations manually. Even if you have your own tests, sooner or later you will get something wrong with time, dates and calendars. Not all days are 24 hours long, shocking, I know :) And this is just the first one on a long list of things that we believe about time, that are simply not true.
If you have to support older Android API levels (lower than 26) you need Android Gradle plugin of at least v4.0.0+ for the Time API to be available (support for core library desugaring).
If you cannot use that for some reason, add the JSR-310 Android Backport (ThreeTen ABP) as a dependency.
This will add the same Time API under the package org.threeten.bp.* with same classes and methods as the Time API, which is otherwise only available on Android from API level 26+ (without support for core library desugaring). Note that the recommended way is to switch to the newest version of the Android Gradle plugin, because this library's support is winding down.
See here:
https://github.com/JakeWharton/ThreeTenABP
I'm having fierce problems trying to get DateUtils.getRelativeTimeSpanString to return what it's supposed to in Android.
I've been through every similar question here and none of the solutions posted are working or relevant.
Here's my code:
CharSequence relativeDate =
DateUtils.getRelativeTimeSpanString(System.currentTimeMillis(),
currentNewsItem.getTimeInMilliseconds(),
DateUtils.HOUR_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
dateView.setText(relativeDate);
The currentNewsItem.getTimeInMilliseconds method does indeed return a long (for example, just now it passed 1521759734 which seems correct) and the getRelativeTimeSpanString passes a correctly formatted date string to the view in the format "March 23, 2018" so it knows the correct date. But I need it to pass "x Hours ago" or "x minutes ago" and I cannot for the life of me figure out why it's not.
I've checked the time on the emulator, and the problem occurs on my device so it's not the timezone settings.
Documentation says that it will revert to a date string like this if the time span is greater than 7 days but I've checked the long that's being passed as the old time and the converter websites shows it's the exact time 4 hours ago. Besides, it's showing the correct date (today), just not the hours/minutes ago.
I've tried the HOUR_IN_MILLIS, MINUTES_IN_MILLIS and SECONDS_IN_MILLIS constants for the third parameter and I've tried removing the last abbreviation parameter and it's still the same result.
I've tried the various public method signatures to try find one that might work but they all have the same result.
Has anyone experienced this or can anyone point out where I'm going wrong?
Many thanks.
If you check DateUtils.getRelativeTimeSpanString, the parameters are listed as:
getRelativeTimeSpanString (long time,
long now,
long minResolution,
int flags)
However in your code,
now: the current time in milliseconds, is passed as 1st parameter instead of currentNewsItem.getTimeInMilliseconds().
To get relative timespan like X minutes ago you can use DateUtils.MINUTE_IN_MILLIS and flag like DateUtils.FORMAT_ABBREV_RELATIVE will abbreviate relative time as X mins. ago.
So, you can change your code to:
CharSequence relativeDate =
DateUtils.getRelativeTimeSpanString(currentNewsItem.getTimeInMilliseconds(),
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS,
DateUtils.FORMAT_ABBREV_RELATIVE);
dateView.setText(relativeDate);
I encounter strange behaviour with Jodatime and Android. I want to parse string:
2014-05-19T18:13:00.000+02:00
to DateTime, and get year, month, hours to int. I started with some test on IntelliJ Studio, and I done something like that:
String date = "2014-05-19T18:13:00.000+02:00";
DateTime dateTime = new DateTime(date);
System.out.println(dateTime.toString());
System.out.println(dateTime.getYear());
System.out.println(dateTime.getMonthOfYear());
System.out.println(dateTime.getDayOfMonth());
System.out.println(dateTime.getHourOfDay());
System.out.println(dateTime.getMinuteOfHour());
System.out.println(dateTime.getMillis());
Which gave me correct answers:
2014-05-19T18:13:00.000+02:00
2014
5
19
18
13
1400515980000
Now, when I changed IDE to Android Studio, and do the same:
String dateT = "2014-05-19T18:13:00.000+02:00";
DateTime dateTime = new DateTime(dateT);
Lo.g(dateTime.getHourOfDay() + "");
Lo.g(dateTime.toString());
my results are:
16
2014-05-19T16:13:00.000Z
For some reason DateTime on Android Studio / Android not take into account the timezone which is +2:00.
I can not find solution for this. Also there is no simple method "addTimeZone" in Joda.
How to display correct time with DataTime? I tried LocalDateTime, construct DateTime with DateTimeZone.getDefault() (which gaves me UTF...)
Since you said that you use the same Joda-Time version on both platforms and regarding the fact that Joda-Time has its own timezone repository independent from system timezone data, there is probably only one explanation left why you observe different behaviour: Different input either explicit or implicit. Let's go into details:
Well, you say, obviously there is the same input given the same input string:
"2014-05-19T18:13:00.000+02:00"
So we have the same (explicit) input. But wait, there is another thing: implicit default settings which can also be considered as kind of input in an abstract way. You use the constructor DateTime(Object). This constructor first delegates to super constructor of class BaseDateTime as you can see in the source code.
public DateTime(Object instant) {
super(instant, (Chronology) null);
}
The javadoc of this super-constructor says:
"Constructs an instance from an Object that represents a datetime,
using the specified chronology. If the chronology is null, ISO in the
default time zone is used.
The recognised object types are defined in ConverterManager and
include ReadableInstant, String, Calendar and Date."
So finally we see that Joda-Time uses the default timezone. This is really the only possibility for different behaviour I can see by studying the source code and the documentation. All other things are equal: Same library version and same explicit string input and same test scenario.
Conclusion: You have different default timezones on your platforms. Note that you get the same instant on both platforms however, just represented with different local timestamps and offsets due to different internal timezone/offset setting inside the DateTime-object.
Update: I have tested the zone overriding behaviour with this code:
String date = "2014-05-19T19:13:00.000+03:00"; // same instant as yours (just with offset +03)
DateTime dateTime = new DateTime(date);
System.out.println(dateTime.toString());
// output: 2014-05-19T18:13:00.000+02:00 (in my default timezone Europe/Berlin)
So the default timezone has precedence over any offset in string input. If you instead want to use the parsed offset then look at using the DateTimeFormatter and its method withOffsetParsed().
This question already has an answer here:
android timezone difference is 1 hour less then expected
(1 answer)
Closed 9 years ago.
I need an offset for "Europe/Russia" to UTC.. in hours. here is my code:
Calendar mCalendar = new GregorianCalendar();
mCalendar.setTimeZone( TimeZone.getTimeZone("Europe/Moscow"));
TimeZone mTimeZone = mCalendar.getTimeZone();
int remote_offset = mTimeZone.getRawOffset()/1000/60/60;
For UTC it should be -4 hours. BUT! some user got 3 hours difference!!
I think, the problem is, Russia doesn't use winter time. And some devices now that, but some not.. how could I implement allway to get "-4" hours?
Regards
First, Russia isn't UTC-4.
The problem has to do with Russia not having daylight saving time. But your issue is probably only happening with android 2.x device and less. The daylight saving time was removed before 4.x as far as I remember (if it's a user input). On the other hand, if you receive a date that was created by the device without user input, you don't have to convert it as it's already as UTC.
But as I said, Russia isn't -4. Russia/Moscow will be +4 hours. But Russia is larger than Moscow really!
Look here: http://en.wikipedia.org/wiki/Time_in_Russia
UTC+03:00 MSK−1: Kaliningrad Time Europe/Kaliningrad
UTC+04:00 MSK: Moscow Time Europe/Moscow, Europe/Volgograd, Europe/Samara
UTC+06:00 MSK+2: Yekaterinburg Time Asia/Yekaterinburg
UTC+07:00 MSK+3: Omsk Time Asia/Omsk, Asia/Novosibirsk, Asia/Novokuznetsk
UTC+08:00 MSK+4: Krasnoyarsk Time Asia/Krasnoyarsk
UTC+09:00 MSK+5: Irkutsk Time Asia/Irkutsk
UTC+10:00 MSK+6: Yakutsk Time Asia/Yakutsk
UTC+11:00 MSK+7: Vladivostok Time Asia/Vladivostok, Asia/Sakhalin
UTC+12:00 MSK+8: Magadan Time Asia/Magadan, Asia/Kamchatka, Asia/Anadyr
So what you'll have to do is to check if we're in winter and that the TimeZone is one of those. If the timezone is one of those, you can add one more hour when you want to show. And remove 1 hour when you want to convert to UTC.
I don't believe it's possible to update the TimeZone on the android phones and that also means that it's not exactly possible to do that unless you find an alternative library for Dates that has timezones built-in and which are updated.
You could subclass the DateObject with the functions that you use to behave just like the old date object, all you'll have to do is to make sure it behaves differently on android2.x and not on android 4.x+.
Also check this: http://www.joda.org/joda-time/
I checked there and I guess it could be usable and less hacky than my suggestion above. The TimeZones are up to date so it could just work for every phone since it shouldn't use the internal timezones. On the other hand, if you have functions that require the Date, it might get tricky.
My suggestion is make sure you use UTC everywhere and use JodaTime to format the date with timezones and to do "datetime" operations. If you make sure that your Java Date never contain a TimeZone other than UTC. It should work.
TimeZone tz = TimeZone.getTimeZone(TimeZoneString);
timeZoneOffsetms = tz.getRawOffset();
The values for TimeZoneString are in the format "GMT+02:00:00"
The previous code was working from 2.2 - 4.1 with not issues.
Now with 4.2 it always returns an offset equal to 0 whether the time zone is ahead or behind UTC.
Any ideas or any one else seen this.
After checking the source for TimeZone there was a significant change in 4.2. The class began enforcing a regex that only requires hours and minutes. Supplying the seconds would result in it failing the regex pattern matcher and then returning null.
The solution on my side is check the value from my server for seconds and remove if they are specified. Since I don't have any control the value returned from the server is.
I hope this helps if any one else has run into the issue.