I am developing a multilingual Struts2 application, and I have quite a few actions which are dealing with Calendar properties. The default type conversion works most of the time, however in some locales I would like to change the default format used.
Specifically I would like to have the dates in English locale to follow the yyyy-MM-dd format. However, this does not work (strangely yyyy-MM-dd HH:mm works fine, but in this case I do not want to have a time part), as Struts2 expect dates in English locale to look different.
So, I would like to change the expected format of the conversion. I am looking for a sane solution for this. The options I have already tried:
A) Own StrutsTypeConverter. This should work, but I could not inject the format specified in the package.properties file into it.
B) Changing the getter/setter pair, to use String instead - works, but this is not a sane solution.
How to fix the solution A? Or is there an alternative approach? Of course, if this can be done entirely in configuration, that would be the best.
Okay, I found a solution for my problem at hand, still, I think this could done in a saner way. Anyway, I am posting my own type converter:
public class DateConverter extends StrutsTypeConverter {
private DateFormat dateFormat;
{
ActionContext ctx = ActionContext.getContext();
ActionSupport action = (ActionSupport) ctx.getActionInvocation().getAction();
String formatString = action.getText("dateformat.ui");
dateFormat = new SimpleDateFormat(formatString);
}
public Object convertFromString(Map context, String[] values, Class toClass) {
String input = values[0];
try {
Date date = dateFormat.parse(input);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal;
} catch (ParseException e) {
return null;
}
}
public String convertToString(Map context, Object object) {
Calendar cal = (Calendar) object;
return dateFormat.format(cal.getTime());
}
}
I removed the non-essential parts of the code, but this is a working solution.
Related
Whenever I want to print out date/time format to a human readable form, IDE will recommend me to use one of the following way
getDateInstance()
getDateTimeInstance()
getTimeInstance()
However, most of the time, applying different int style doesn't meet my requirement. End up, I need to define my own.
private static final ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal <SimpleDateFormat>() {
#Override protected SimpleDateFormat initialValue() {
// January 2
return new SimpleDateFormat("MMMM d");
}
};
This create a trouble for me, if I want to support non-English as well. For instance, for Chinese market, I need to use separate format.
private static final ThreadLocal<SimpleDateFormat> dateFormatForChineseThreadLocal = new ThreadLocal <SimpleDateFormat>() {
#Override protected SimpleDateFormat initialValue() {
// 1月2日
return new SimpleDateFormat("MMMMd日");
}
};
My code will end up with the following
public String dateString() {
if (chinese user) {
return dateFormatForChineseThreadLocal.get().format(calendar.getTime());
}
return dateFormatThreadLocal.get().format(calendar.getTime());
}
This make maintenance job difficult. I was wondering, is there a better way, to customize date/time display format for different localization?
When you localize your app you usually create strings.xml files for each language your app shall support in /src/main/res/, where values/ contains mostly english files and in values-de or values-cn german or chinese for instance. When you define a string resource with your format there, you can simply read that out and pass that format to your date formatter.
With this, you can simply add new languages without changing any line in your code.
I have a rest service which validates date now i need to modify it to take two dates, but i don't know if to use #PathParam or #QueryParam and if i can insert it between two #PathParam
This it the original code :
#Path("isDateValid/{date}/{itemId}")
public boolean isDateValid(#PathParam("date") Date date, #PathParam("itemId") Long itemId) {
Should i do like this :
#Path("isDateValid/{startDate}/{endDate}/{itemId}")
public boolean isDateValid(#PathParam("startDate") Date startDate, #PathParam("endDate") Date endDate, #PathParam("itemId") Long itemId) {
If you do not want to use third party stuff, I suggest you define a format for the text-date. You can use the SimpleDateFormat class (avoid the space). The you can use the following code.
#Path("isDateValid/{itemId}")
public boolean isDateValid(#PathParam("itemId") Long itemId) {
#QueryParam("begin") String sBegin;
#QueryParam("end") String sEnd;
SimpleDateFormat sdf = new SimpleDateFormat(/* Your patern, for example "yyMMddHHmmssZ"*/);
Date dBegin = sdf.parse(sBegin);
Date dEnd = sdf.parse(sEnd);
/*
...
*/
}
Date Class is cannot serialize using JAX-RS as it is not a simple type. You need to develop the same using MessageBodyReader/Writer .
Click Here for more
Or you can use some third party stuff to configure to get it done.
Click Here for more
Why does this code return 0001-02-05?
public static String getNowDate() throws ParseException
{
return Myformat(toFormattedDateString(Calendar.getInstance()));
}
I changed the code to:
public static String getNowDate() throws ParseException
{
Calendar temp=Calendar.getInstance();
return temp.YEAR+"-"+temp.MONTH+"-"+temp.DAY_OF_MONTH;
}
And now it returns 1-2-5.
Please, help me get the actual date. all i need is the Sdk date.
Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH are int constants (just look up in the API doc)...
So, as #Alex posted, to create a formatted String out of a Calendar instance, you should use SimpleDateFormat.
If however you need the numeric representations of specific fields, use the get(int) function:
int year = temp.get(Calendar.YEAR);
int month = temp.get(Calendar.MONTH);
int dayOfMonth = temp.get(Calendar.DAY_OF_MONTH);
WARNING! Month starts from 0!!! I've made some mistakes because of this!
Use SimpleDateFormat
new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime());
You are using constants to be used with the Calendar.get() method.
Why not use SimpleDateFormat?
public static String getNowDate() {
return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
}
You are doing it wrong. Change to:
return temp.get(Calendar.YEAR)+"-"+ (temp.get(Calendar.MONTH)+1) +"-"+temp.get(Calendar.DAY_OF_MONTH);
Also, you may want to look into Date:
Date dt = new Date();
//this will get current date and time, guaranteed to nearest millisecond
System.out.println(dt.toString());
//you can format it as follows in your required format
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(dt));
i want to use standard class called DateFormat which has subclass SimpleDateFormat TO write a method called convert which returns a String in the form dd.mm.yy: when passed a GregorianCalendar with a specific date
public String convert (Calendar gc) { ... }
For example, when myGC is a GregorianCalendar variable representing the 25th of December 2006, String s = convert(myGC); should set s to the string "25.12.06".
and i'm having trouble to write a convert method on this
public String convert(Calendar c) {
return new SimpleDateFormat("dd.MM.yy").format(c.getTime());
}
Eventually you'll want to store that SimpleDateFormat as a member (for example) if performance becomes a concern.
Why not just use a pattern like this one "dd.MM.yy" in your SimpleDateFormat ?
DateFormat dateFormatter = new SimpleDateFormat("dd.MM.yy");
String myDate = dateFormatter.format(cal.getTime());
E.g. eng, spa, ita, ger
I could iterate all locales and compare the codes, but I wonder whether there is a more elegant & performant way to achieve this....
Thanks a lot for any hints :)
I don't know if there's an easy way to convert the 3-letter to the 2-letter versions, but in a worse case scenario, you could create a Map of them, like so:
String[] languages = Locale.getISOLanguages();
Map<String, Locale> localeMap = new HashMap<String, Locale>(languages.length);
for (String language : languages) {
Locale locale = new Locale(language);
localeMap.put(locale.getISO3Language(), locale);
}
Now you can look up locales using things like localeMap.get("eng");
Edit: Modified the way the map is created. Now there should be one object per language.
Edit 2: It's been a while, but changed the code to use the actual length of the languages array when initializing the Map.
You can use constructor Locale(String language), where language is the 2 letter ISO-639-1 code. I think the easiest way to convert ISO-639-2 to ISO-639-1 would be to create HashMap<String,String> constant.
Some modified code from my project, which has a similar requirement. We have our own historical timezone format so we can't use standard libraries.
public class MyProjectTimeZoneFactory {
private static Map timeZoneDb;
/**
* Set up our timezone id mappings; call this from any constructor
* or static method that needs it.
*/
private static void init() {
if(null == TimeZoneDb) {
timeZoneDb = new HashMap(); // Maybe a TreeMap would be more appropriate
timeZoneDb.put(" ","GMT+00");
timeZoneDb.put("EAD ","GMT+10");
timeZoneDb.put("JST ","GMT+9");
// etc.
}
}
public static TimeZone getTimeZone(String id)
throws CommandFormatException {
init();
TimeZone tz;
if(timeZoneDb.containsKey(id)) {
tz = TimeZone.getTimeZone((String)timeZoneDb.get(id));
} else {
throw new CommandFormatException("Invalid Timezone value");
}
return tz;
}
}
You could argue that it would be better to have the map in configuration rather than code - perhaps in a properties file. That may be true - but do remember the Pragmatic Programmers' rule 'Your not going to need it'.