Problem- My application is used in a production environment across a few hundred computers. The issue arose after installing some new computers and finding out that my application was crashing on ONLY the new computers. The new computers came with JAVA v8u5, in attempts to fix the issue I also installed v7u55 (I thought it might be a versioning issue).
NOTE* I'm compiling using JDK v7u45 **
Root Cause- The failing code is a call to the Calendar.getDisplayName(int, int, Locale)
Code That is failing:
System.out.println("Getting calendar instance");
Calendar instanceCalendarObj = Calendar.getInstance();
String date = instanceCalendarObj.getDisplayName(Calendar.MONTH, 0, Locale.ENGLISH);
date = date.concat(" "+String.valueOf(instanceCalendarObj.get(Calendar.DAY_OF_MONTH)));
date = date.concat(", "+String.valueOf(instanceCalendarObj.get(Calendar.YEAR)));
JOptionPane.showMessageDialog(this, date);
Error Message:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException
at java.util.Calendar.checkDisplayNameParams(Unknown Source)
at java.util.Calendar.getDisplayName(Unknown Source)
Any help would be greatly appreciated, even if its just a workaround.
You pass a wrong parameter to the getDisplayName() method.
The second parameter is the style, whose possible values are Calendar.SHORT and Calendar.LONG. Use these constants as seen below:
Calendar c = Calendar.getInstance();
c.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.ENGLISH);
c.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH);
Btw, the constant values for Calendar.SHORT and Calendar.LONG are 1 and 2 (and you passed 0 in your code). But always use the constant names and not their values!
Related
We want to add days to the current date and format it in a specific way. This was solved in Groovy 2.4.13 and the following date manipulation works fine:
today = new Date()+90;today.format('yyyy-MM-dd HH:mm:ss.S');
Result: 2019-12-02 08:07:15.294
In Groovy 2.5.4 the same expression throws this exception:
groovy.lang.MissingMethodException: No signature of method:
java.util.Date.plus() is applicable for argument types: (Integer)
values: [90] Possible solutions: parse(java.lang.String),
split(groovy.lang.Closure), use([Ljava.lang.Object;),
is(java.lang.Object), wait(), clone() at
Script1.run(Script1.groovy:3)
I was able to reproduce this behaviour in "Groovy sandboxes" online:
Working fine here: groovy-playground (Version 2.4.1.5)
Failing here: groovyconsole (Version 2.5.7)
What is the working alternative in this case? I have read about a new Date API, but couldn't find the details about how to use it, with date manipulation (+ 90 days for example).
Take a look at TimeCategory
import groovy.time.TimeCategory
def theDate = use(TimeCategory){new Date() + 90.days}.format('yyyy-MM-dd HH:mm:ss.S')
I agree with Ole V.V.'s recommendations to use the new Date/Time API. Here is how you would write his Java sample in a more Groovy style.
// you can assemble aggregate types by left shifting the aggregates
// I'm not endorsing this approach, necessarily, just pointing it out as an alternative
ZonedDateTime now = LocalDate.now() << LocalTime.now() << ZoneId.of('Africa/Bamako')
// the plus operator is overloaded
ZonedDateTime in90Days = now + 90
// you can pass a String to format without needed a full DateTimeFormatter instance
println in90Days.format('uuuu-MM-dd HH:mm:ss.S')
While Groovy adds some further support for the old Java Date class, I still believe that you should not use it. It was always poorly designed and is now long outdated. Instead use java.time, the modern Java date and time API. I am sorry that I will have to trust you to translate from Java code.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S");
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Africa/Bamako"));
ZonedDateTime in90Days = now.plusDays(90);
System.out.println(in90Days.format(formatter));
Output when running just now was:
2020-01-01 08:37:13.3
Please substitute your desired time zone if it didn’t happen to be Africa/Bamako.
Link: Oracle tutorial: Date Time explaining how to use java.time.
You can use Calendar to achieve that
Calendar cal = new GregorianCalendar();
cal.add(Calendar.DATE, 90);
Date date = cal.getTime();
All steps must be separate and not in a single line.
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())));
I am currently struggling to refactor this piece of old code to use the new java.time.format.DateTimeFormatter because it is used in our main logging component where this creates unnecessary garbage.
private String getFormattedDate(final Date date) {
// a new instance is created foreach log message
SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
return dateFormat.format(date);
}
I already tried the new ISO_INSTANT formater like:
DateTimeFormatter.ISO_INSTANT.format(date.toInstant());
but this gives (slightly) different output as before.
My test shows:
Expected: is "2013-10-22T05:23:48.397+0200"
but: was "2013-10-22T03:23:48.397Z"
So I need the time zone offset to be included in the format string as shown in Expected.
I know about the DateTimeFormatterBuilder but I didnt manage to build it in a way to get my desired format output.
How would I need to do this?
I know I can always fall back to using a single thread local SimpleDateFormat instance but I would like to use the new java.time stuff :-)
Date date = new Date();
System.out.println(DateTimeFormatter.ISO_INSTANT.format(date.toInstant()));
// output: 2015-11-22T14:46:08.776Z
System.out.println(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(
date.toInstant().atZone(ZoneId.systemDefault())));
// output: 2015-11-22T15:46:08.776+01:00
System.out.println(DateTimeFormatter.ISO_OFFSET_DATE_TIME
.withZone(ZoneId.systemDefault())
.format(date.toInstant()));
// output: 2015-11-22T15:46:08.776+01:00
I'm trying to retrieve a list of events from a google calendar, using the Java api (jar version v3-rev9-1.7.0-beta)
This code works fine
Events e = service.events().list("primary").
setMaxResults(3).
execute();
where service is a Calendar object.
However, if I add a setTimeMin or setTimeMax parameter, like this
Date now = new java.util.Date();
Events e = service.events().list("primary").
setTimeMin(new DateTime(now)).
setMaxResults(3).
execute();
it returns a failure message, "Bad Request".
(note that as of this version, the setTime functions take a google DateTime object. I've also tried with the previous version of the jar, which takes a string, but received the same message).
So I was just wondering if anyone has successfully used these functions - perhaps they're not supposed to be called in this manner? Is there a way to get more detail back on the error?
Thanks :)
DateTime startTime = new DateTime(new Date(), TimeZone.getDefault());
Sorts the problem
I also encountered this. It seems the format of the DateTime.toString() or DateTime.toStringRfc3339() methods are incorrect as input to setTimeMin().
The DateTime.toString() format is:
2012-07-04T21:02:16.590
yyyy-MM-dd'T'HH:mm:ss.SSS (SimpleDateFormat notation)
The format which it expects seems to be close to xsd:datetime format (whatever that is):
2012-07-04T21:02:16Z (zulu, gmt)
2012-07-04T21:02:16-07:00 (mst, -7h)
2012-07-04T21:02:16-0700 (it also works without the colon in the timezone)
yyyy-MM-dd'T'HH:mm:ssZ (SimpleDateFormat)
Formatting can be done with a SimpleDateFormat:
SimpleDateFormat FMT_TIME=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String fromTimeStr=FMT_TIME.format(new Date());
Events evts = client.events().list(cal.getUid()).setTimeMin(fromTimeStr)
.execute();
Now, since I'm using the older API, I'm not sure how this would be done if the only method is setTimeMin(DateTime), but this should get you closer.
The Google documentation or source should mention this somewhere.
So I'm modifying one of the opensource Google I/O opensource applications (2010) and I'm getting the following error when trying to sync the app with using custom Google spreadsheet, same headings different data (appears to sync fine with the default Google spreadsheet)
"Sync error: Problem parsing timestamp: java.text.ParseException: Unparseable date: "null 2010 10:45am -0700"
This is the Java Code that's throwing the error
private static long parseTime(String date, String time) throws HandlerException {
final String composed = String.format("%s 2010 %s -0700", date, time);
try {
return sTimeFormat.parse(composed).getTime();
} catch (java.text.ParseException e) {
throw new HandlerException("Problem parsing timestamp", e);
}
}
Here's links to the information (Atom) which it is trying to parse:
My Data
https://spreadsheets.google.com/feeds/worksheets/0AmvmSNjQXtJFdE1lTlFxVXZCLUN0OFpqa3oyM2d4bEE/public/basic
Google Data
http://spreadsheets.google.com/feeds/worksheets/twd6syM493oFqIFWeIm8qGw/public/basic"
I can't figure out why I'm getting this error. Any help would be greatly appreciated.
Check the parameter date you pass into this method. It seems to be null, which obviously is not a valid date.
Because #henrik has already posted what your actual current problem is, I'm giving a few recommendations based on your posted code:
You're using sTimeFormat, which must be at least a static variable, and is probably final as well (and usually should be, in this context). However, you aren't following naming conventions -it should probably be named TIMESTAMP_FORMATTER (if the only thing you do is get an actual date, use TIMESTAMP_PARSER). Also, although you're not likely to be using multiple threads on an android device, please be aware DateFormat and SimpleDateFormat are NOT threadsafe - the standard practice is to contruct a copy for each use.
You're manually formatting the timestamp itself, before attempting to parse it. There's no point - you should be using the existing data (eiither from the xml directly, or the rendered html), and supplying a custom formatting string.
You're setting two parts of the dates, year and timezone. At minimum, that should be moved outside of the actual parse piece. You should probably write a setToCanonicalDate method or something that takes the output from your parsing and sets it to the valid year and timezone. And how far are you distributing that app? I live in the Pacific Timezone - your default won't do me any good.
This is how you can work with time and long:
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_MONTH, dp.getDayOfMonth());
c.set(Calendar.MONTH, dp.getMonth());;
c.set(Calendar.YEAR, dp.getYear());
long l = c.getTime().getTime();