Java DateFormat.SHORT in Android not working as expected - java

I want the "correct" localized time for users with US or German system locale. Meaning "1:00 PM" and "13:00"
Java API says: https://docs.oracle.com/javase/tutorial/i18n/format/dateFormat.html
Formats U.S. Locale German Locale
DEFAULT 7:03:47 AM 7:03:47
SHORT 7:03 AM 07:03
Correct so far.
Android API: https://developer.android.com/reference/java/text/DateFormat.html
SHORT is completely numeric, such as 12.13.52 or 3:30pm
Correct for US, if you set a German Locale, Android will "translate" AM/PM and not remove it, how the correct way is and how Java did it.
My question, why does Google do that? Am I stupid and lacking sleep, not to understand "the Google logic"? This is a trivial request, yet I tried for 2 hours to get a correct German short time presentation, that would also work for US localization. "13:57 nachm." is NOT a German time representation. No one uses that, that's why we have a 24 hour formating system. It's so awkward that it breaks every reading attempt.
Test code:
private void testGoogleLocaleLogic() {
TimeZone tz_de = TimeZone.getTimeZone("Europe/Berlin");
Calendar c_us = Calendar.getInstance(tz_de,Locale.US);
Calendar c_de = Calendar.getInstance(tz_de,Locale.GERMAN);
java.text.DateFormat df_date_us_short_ = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT,Locale.US);
java.text.DateFormat df_date_de_short = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT,Locale.GERMAN);
c_us.set(Calendar.YEAR,2018);
c_us.set(Calendar.MONTH,2);
c_us.set(Calendar.DAY_OF_YEAR,6);
c_us.set(Calendar.HOUR_OF_DAY,13);
c_de.set(Calendar.YEAR,2018);
c_de.set(Calendar.MONTH,2);
c_de.set(Calendar.DAY_OF_YEAR,6);
c_de.set(Calendar.HOUR_OF_DAY,13);
Log.d("localeTest","Android Dateformat getTimeInstance SHORT US: " + df_date_us_short_.format(c_us.getTime()));
Log.d("localeTest","Android Dateformat getTimeInstance SHORT DE: " + df_date_de_short.format(c_de.getTime()));
Log.d("localeTest","df_date_de_short is type of: " + df_date_de_short.getClass().getName());
}
Results in
Android Dateformat SHORT US: 1:57 PM
Android Dateformat SHORT DE: 1:57 nachm.
Why it's not 13:57 for German locale, although I set it two times in Calendar and DateFormat is also beyond my knowledge.
A solution to print out minutes and hours manually and then switch case between system locales to add or hide "PM/AM" is exactly why people invented Locales in the first place. To avoid that. Please tell me this is not the case.
UPDATES/MORE TESTING/MORE RESEARCH (forced use of java.text....):
My Moto X Style, Android 7, German locale prints:
Android Dateformat getTimeInstance SHORT US: 1:29 PM
Android Dateformat getTimeInstance SHORT DE: 1:29 nachm.
df_date_de_short is type of: java.text.SimpleDateFormat
Android Emulator NEXUS_5_API_26, US locale
Android Dateformat getTimeInstance SHORT US: 1:18 PM
Android Dateformat getTimeInstance SHORT DE: 13:18
df_date_de_short is type of: java.text.SimpleDateFormat
So the forced use of "java.text.SimpleDateFormat" works, but only on an emulator, not in real world? I'm close, maybe someone has the last 5 cents!

My guess earlier was right, sadly. If you don't search for it with this "guess", you'll never find it as date formatting is such a common topic. Long story short, it's an Android bug:
https://issuetracker.google.com/issues/37054851
It was fixed over a year ago. That's why the emulator works, but devices before API27 won't have the fixes as OEM don't care.
Google employee added this workaround in above bug report:
boolean use24Hour = android.text.format.DateFormat.is24HourFormat(context);
final String skeleton = use24Hour ? "Hm" : "hm";
final String pattern = android.text.format.DateFormat.getBestDateTimePattern(locale, skeleton);
DateFormat formatter = new SimpleDateFormat(pattern, locale);
... for SHORT date. MEDIUM would use skeletons of "Hms" / "hms" instead.
The code above bypasses the internal code that keep the (incorrect) in-memory state that tracks whether the user prefers 12 or 24 hour time formatting. AFAIK, android.text.format.DateFormat.is24HourFormat has always used the underlying user setting.
is24HourFormat() was added in API 3. getBestDateTimePattern() was only added in API 18.
That's exactly the switch case crap I feared humanity has to use in the year of 2018. We want to live on Mars, yet we can't figure out how to print time on planet Earth!

why don't u try using SimpleDateFormat
instead of using default DateFormat? maybe you can do something like this:
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
dateFormat.setTimeZone(tz_de);
Log.d("localeTest",dateFormat.format(c_us.getTime())));

Related

How would I format dates of different languages to get the difference between the current day and a day in the future?

So the goal is to be able to get the current date (no problem there) and compare it to a date coming in, which can be either the current date or a date in the future. Not only that, but because of how other languages write out or structure dates, the date string that comes in can change format-wise depending on the language.
If the device is set to English, the string comes in like so:
"Monday, January 30, 2023"
But if the device is set to French, the string looks like this instead:
"lundi 30 janvier 2023"
... and Spanish like this:
"lunes, 30 de enero de 2023"
... and so on. Italian is slightly different, and I've also tried German, which is also slightly different.
I did try DateFormat with DateFormat.LONG and Locale.getDefault() as the parameters (so that it would always use the Locale the device is set to and will always get the full date) but it throws an "unparsable date" error for every language, even the English string.
How would I take any of the given strings above and format them in a way that I can compare the date to the current date (a value like LocalDate.now())? Is there an overarching way to do so across languages, or do I need to create formats for all of these? The purpose is to see how far out the date asked for is from the current date to adjust what is visible in my app (done based on days - is the asked for date 3 days out from the current date? 4 days? 5?).
Thanks in advance for any and all help and insight!
You must to configure your dates patterns for each language (Locale) => This output is exactly what you want, try to adapt it with your function need :
public static void main(String[] args) {
Locale enLocale = Locale.UK;
String datePatternForEn = "EEEE', 'MMMM', 'dd yyyy";
Locale frLocale = Locale.FRANCE;
String datePatternForFr = "EEEE dd MMMM yyyy";
Locale spLocale = new Locale("es", "ES");
String datePatternForSp = "EEEE',' dd' de 'MMMM' de 'yyyy";
DateTimeFormatter englishDateFormat = DateTimeFormatter.ofPattern(datePatternForEn, enLocale);
DateTimeFormatter frenchDateFormat = DateTimeFormatter.ofPattern(datePatternForFr, frLocale);
DateTimeFormatter spanishDateFormat = DateTimeFormatter.ofPattern(datePatternForSp, spLocale);
System.out.println(LocalDate.now().format(englishDateFormat));
System.out.println(LocalDate.now().format(frenchDateFormat));
System.out.println(LocalDate.now().format(spanishDateFormat));
}

SimpleDateFormat question for timezone offset +AA:BB

I am currently using the following SimpleDateFormat pattern:
String DATE_TIME_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss,SSSXXX";
This works fine, however some raspberry Pi java implementations don't recognize it properly:
timestamp 2020-01-21T09:41:45,434Z
In most cases, this won't be an issue, however the offset is buggy for some raspberry PIs; I don't want that. Is there an alternative pattern with the same offset format (+/-HH:mm) that could work? I've tried all kinds of patterns, but none seem to produce the same output.
I also used the following tool to search for such a pattern: https://javadevtools.com/simpledateformat , though it was fruitless.
NOTE: An example output of this format is 1997-07-16T19:20:30,45+01:00 , with a colon in the offset.
If you were using java.time, especially the two classes java.time.OffsetDateTime (pattern symbols are explained in this JavaDoc) and java.time.format.DateTimeFormatter, you or your Raspberry Pi would be able to correctly parse the timestamp (which has a strange format using a comma to separate fractions of second from the seconds).
The following example parses your timestamp and outputs the default format:
public static void main(String[] args) {
String timestamp = "1997-07-16T19:20:30,45+01:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[,SSS]xxx");
OffsetDateTime odt = OffsetDateTime.parse(timestamp, dtf);
System.out.println(odt);
}
Output:
1997-07-16T19:20:30.450+01:00
I confirm that this is not a Pi issue. I switched my local time zone to UTC and ran the following example:
long current = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss,SSSXXX");
Date date = new Date(current);
String parsed = format.format(date);
System.out.println(parsed);
2020-08-31T15:05:27,872Z
And the Z appeared, on Windows 10. I have missed that part of the ISO spec. It seems I have to workaround my tests for this situation :). Thanks everyone!

Selenium JAVA : How to validate a frequently changing data in the front end?

The website that I am automating has a data which is something like,
"Delivery Sep 06 Thursday"
The date keeps changing everyday. I now have to validate it's presence and the message format.
Any help on this is appreciated.
Try this:
public String getCurrentDate() {
//Delivery Sep 06 Thursday
String format = "MMM dd EEEEE";
SimpleDateFormat formatCurrentDate = new SimpleDateFormat(format, Locale.ENGLISH);
Calendar userDate = Calendar.getInstance();
return formatCurrentDate.format(userDate.getTime());
}
public void checkDeliveryDate() throws Exception {
String searchString = "Delivery " + getCurrentDate();
driver.isElementPresent(By.xpath("//div[.='"+searchString+"'])"));
}
You have 2 options:
If you know what's a formula behind expected date (for example: always same day; always 3 days from now, or even some more complicated rules), then your test can generate expected date much like the site does, and validate that date displayed on the site is the same as your expected date.
If you don't know the formula, it's too complicated, or changes too often, then you can validate 3 things:
That date is displayed in proper format (e.g. you could check that its format is Delivery MMM DD EEEE)
Date and day of the week match (e.g. check that Sep 06 is indeed Thursday)
Date is within acceptable range (e.g. +/- week from current date, or whatever makes sense)
Those are general rules. If you want a more specific advice, please post HTML code, and some logic behind expected dates.

How can I get the current time in particular format, for a particular zone?

I want to get the current DateTime in a zone of my choice and in a particular format (eg HH-MM-SS, MM-DD-YY, MoMo-DD-YY-HH-MM-SS etc).
How can I do this, using JodaTime?
Given that you've already seen the user guide (which includes sections on time zones and formatting), it's not really clear where your confusion is. Some sample code to get you going:
DateTimeZone zone = DateTimeZone.forID("Europe/London");
DateTime currentTimeInLondon = new DateTime(zone);
DateTimeFormatter formatter = DateTimeFormat.forPattern("HH:mm:ss, MM-dd-yyyy");
String text = formatter.print(currentTimeInLondon); // e.g. 08:24:54, 09-26-2012
It would be worth you taking some time to analyze why you couldn't get to this code yourself, given the information in the user guide. Being able to work out how to use APIs is a very important skill as a software engineer - you mustn't expect to be spoonfed code all the time.
this may help you.
http://joda-time.sourceforge.net/userguide.html
Use following code to get time according to particular zone with format.
Locale locale = Locale.FRENCH;
// Format with a custom format
DateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy", locale);
String s = formatter.format(new Date());
// mar., 29 sept. 2012
// Format with a default format
s = DateFormat.getDateInstance(DateFormat.MEDIUM, locale).format(new Date());
// 29 sept. 2012

how to set getCreatedAt(); date object in android textview?

how do you set the twitter4j date object in android? seems pretty straight forward in java but cant make this work on android, the twitter4j javadoc can be found here http://twitter4j.org/en/javadoc/twitter4j/Status.html
Date tweettime = result.getCreatedAt();
textview.setText(""+ tweettime);
Showing a date on Android is hardly different from showing it in a JVM.
Just use a SimpleDateFormat to specify the format of the date. Also, make sure that any UI changes (to your textview) are done on the UI Thread.
Twitter4j has a friendly helper class to transform the date created Date object into something more user readable. It's close to the format twitter uses to show the date;
I made a method you can use:
/*converts standard date to user readable date such as 5m ago, 30 mins ago, 1 hr ago etc*/
private String formatDate(Date create_date){
//twitter date format from json response: Wed Jul 31 13:15:10 EDT 2013
TimeSpanConverter converter = new TimeSpanConverter();
return converter.toTimeSpanString(create_date);
}
You will need to import: import twitter4j.util.TimeSpanConverter;
Try this:
TimeSpanConverter converter = new TimeSpanConverter();
dateTextView.setText(converter.toTimeSpanString(status.getCreatedAt()));

Categories