JXL and Timezone writing an Excel - java

I try to create an Excel sheet with jxl.
One of my field is a Date, and I live in GMT+1 TimeZone
I use something like this to do it:
WritableCellFormat EXCEL_DATE_FORMATTER = new WritableCellFormat(new DateFormat("dd/MM/yyyy hh:mm"));
...
WritableCell cell = null;
cell = new jxl.write.DateTime(col, row, date);
cell.setCellFormat(EXCEL_DATE_FORMATTER);
The date is writing in the correct format but with a -1 hour value (in GMT)
I try to find a solution and i found this
http://www.andykhan.com/jexcelapi/tutorial.html#dates
But I can't pass a SimpleDateFormat to a DateCell.
There is a way to do it?
Now I using java.util.Calendar to add an hour, but is an horrible solution.
Thank for help!

The jxl.write.DateTime class has several constructors (cf. API).
By default, it will use your system TimeZone to modify the date. You can pass to the constructor a jxl.write.DateTime.GMTDate object to disable this. Here is the code you should use:
WritableCell cell = null;
cell = new jxl.write.DateTime(col, row, date, DateTime.GMT);

Yesterday I had a same issue. I live in CET time zone (Central European Time) and simple creation of the DateTime cell moved the time about one hour.
At first I tried to set the timezone on GMT as is suggested in the official tutorial.
final DateFormat valueFormatDate = new DateFormat( "dd.MM.yyyy HH:mm" );
valueFormatDate.getDateFormat().setTimeZone( TimeZone.getTimeZone( "GMT" ) );
It appears not to be working. The time modification was still same. So I tried to set up correct timezone to match the timezone in a Date object.
final DateFormat valueFormatDate = new DateFormat( "dd.MM.yyyy HH:mm" );
valueFormatDate.getDateFormat().setTimeZone( TimeZone.getTimeZone( "CET" ) );
This worked perfectly as I expected. But the things not to be too easy, there is except CET timezone also CEST (Central European Summer Time) which moves the time about another hour. When I tried to use dates in CEST time, it didn't worked again because there was one hour addition to the expected base. I guess that it would be solution to set up "CEST" timezone instead of "CET" for them but I didn't figure out how to get the proper timezone from the Calendar, it always returned CET.
Anyway finally I used a not nice, but reliably working solution.
I have a factory method for date cell to have a configuration on one single place
in that method, I convert the given Date to be in GMT timezone at first
set up the timezone format to GMT
disable timezone modification on DateTime cell.
These steps are not absolutely clean but it works for CET as well as CEST dates. The final code is here:
public class DateUtils {
// formatter to convert from current timezone
private static final SimpleDateFormat DATE_FORMATTER_FROM_CURRENT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
// formatter to convert to GMT timezone
private static final SimpleDateFormat DATE_FORMATTER_TO_GMT = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
static {
// initialize the GMT formatter
final Calendar cal = Calendar.getInstance( new SimpleTimeZone( 0, "GMT" ) );
DATE_FORMATTER_TO_GMT.setCalendar( cal );
}
public static Date toGMT( final Date base ) {
try {
// convert to string and after that convert it back
final String date = DATE_FORMATTER_FROM_CURRENT.format( base );
return DATE_FORMATTER_TO_GMT.parse( date );
} catch ( ParseException e ) {
log.error( "Date parsing failed. Conversion to GMT wasn't performed.", e );
return base;
}
}
}
And there is a factory method
/** builds date cell for header */
static WritableCell createDate( final int column, final int row, final Date value ) {
final DateFormat valueFormatDate = new DateFormat( "dd.MM.yyyy HH:mm" );
valueFormatDate.getDateFormat().setTimeZone( TimeZone.getTimeZone( "GMT" ) );
final WritableCellFormat formatDate = new WritableCellFormat( valueFormatDate );
// create cell
return new DateTime( column, row, toGMT( value ), formatDate, DateTime.GMT );
}

Related

Local to GMT and vice versa- Date and time conversion not working

I was trying to convert input date time to GMT+0 , later convert that back to its local time. Though local to GMT+0 conversion works, the later conversion-gmt to local fails!
Calendar cal=Calendar.getInstance();
cal.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println("my inputTime:"+ sdf.format(cal.getTime()));
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("gmt+0 converted time:"+ sdf.format(cal.getTime()));
//now i want to get my local time from this converted gmt+0 standard time
String standdardTimeStr=sdf.format(cal.getTime());
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date date=sdf2.parse(standdardTimeStr);
Calendar cal2= Calendar.getInstance();
cal2.setTime(date);
System.out.println("standard input time:"+ sdf2.format(cal2.getTime()));
sdf2.setTimeZone(TimeZone.getTimeZone("GMT+6")); //or Asia/Dhaka
System.out.println("gmt+6 convertedtime:"+ sdf2.format(cal2.getTime()));
And this is my output:
my inputTime:2020-07-13T15:02:16.849
gmt+0 converted time:2020-07-13T09:02:16.849
standard input time:2020-07-13T09:02:16.849 //taking upper line as input-gmt+0
gmt+6 convertedtime:2020-07-13T09:02:16.849 //this date was supposed to be same as the first date
Please point out what am I doing wrong in coding or conceptually?
Just for the case you want a solution with a modern API, see this commented example:
public static void main(String[] args) {
// provide some fix example datetime String
String dateTime = "2020-05-08T13:57:06.345";
// create the two time zones needed before
ZoneId utc = ZoneId.of("UTC"); // UTC = GMT (+0)
ZoneId local = ZoneId.systemDefault(); // the zone of your JVM / system
/*
* then parse the String which doesn't contain information about a zone
* to an object that just knows date and time
*/
LocalDateTime ldt = LocalDateTime.parse(dateTime);
// and use that to create a zone-aware object with the same date and time
ZonedDateTime utcZdt = ZonedDateTime.of(ldt, utc);
// finally adjust its date and time by changing the zone
ZonedDateTime localZdt = utcZdt.withZoneSameInstant(local);
// then print both results
System.out.println(utcZdt + "\t==\t" + localZdt);
// and maybe try to use a different output format by defining a custom formatter
DateTimeFormatter gmtStyleDtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSO");
System.out.println(utcZdt.format(gmtStyleDtf)
+ "\t==\t" + localZdt.format(gmtStyleDtf));
}
which ouputs the following lines on my system (might be different on yours due to different time zones):
2020-05-08T13:57:06.345Z[UTC] == 2020-05-08T15:57:06.345+02:00[Europe/Berlin]
2020-05-08T13:57:06.345GMT == 2020-05-08T15:57:06.345GMT+2
EDIT:
Here's a possibility of doing the same thing but just dealing with offsets instead of time zones:
public static void main(String[] args) {
// provide some fix example datetime String
String dateTime = "2020-05-08T13:57:06.345";
// create the two offsets needed
ZoneOffset gmt = ZoneOffset.ofHours(0); // UTC = GMT (+0)
ZoneOffset gmtPlusSix = ZoneOffset.ofHours(6); // Asia/Dhaka ;-)
/*
* then parse the String which doesn't contain information about a zone
* to an object that just knows date and time
* NOTE: this just parses the String and does nothing else
*/
LocalDateTime justDateAndTime = LocalDateTime.parse(dateTime);
// and use that to create an offset-aware object with the same date and time
OffsetDateTime dateAndTimeAndGmtPlusSix = OffsetDateTime.of(justDateAndTime, gmtPlusSix);
// finally adjust its date and time by changing the offset keeping the instant
OffsetDateTime dateAndTimeInGmt = dateAndTimeAndGmtPlusSix.withOffsetSameInstant(gmt);
// then print both results
System.out.println(dateAndTimeAndGmtPlusSix + "\t==\t" + dateAndTimeInGmt);
// and maybe try to use a different output format by defining a custom formatter
DateTimeFormatter gmtStyleDtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSO");
System.out.println(dateAndTimeAndGmtPlusSix.format(gmtStyleDtf)
+ "\t==\t" + dateAndTimeInGmt.format(gmtStyleDtf));
}
Output:
2020-05-08T13:57:06.345+06:00 == 2020-05-08T07:57:06.345Z
2020-05-08T13:57:06.345GMT+6 == 2020-05-08T07:57:06.345GMT
Note that a Z is equivalent to an offset of GMT/UTC +0.
This way, you could create a method like
public static String convert(String datetime, int fromOffset, int toOffset) {
ZoneOffset fromZoneOffset = ZoneOffset.ofHours(fromOffset);
ZoneOffset toZoneOffset = ZoneOffset.ofHours(toOffset);
OffsetDateTime odt = LocalDateTime.parse(datetime).atOffset(fromZoneOffset);
return odt.withOffsetSameInstant(toZoneOffset)
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
maybe handle invalid argument values, use it like this
public static void main(String[] args) {
String dateTime = "2020-05-08T13:57:06.345";
System.out.println(convert(dateTime, 6, 0)));
}
and receive the output
2020-05-08T07:57:06.345
I don't know why you're using a Calendar object. Javadoc of Calendar.getInstance() says:
The Calendar returned is based on the current time in the default time zone
Which means that calling cal.setTime(new Date()); is entirely redundant.
But, even worse than that, the following three are all the same:
// The very long way
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
Date date = cal.getTime();
// The long way
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
// The simple way
Date date = new Date();
A Date object always stores the date/time in UTC (GMT+0). Time zones are applied when a string is parsed, and when a string is formatted.
Parsing a string that doesn't specify a time zone offset will be parsed in the time zone of the SimpleDateFormat, which is the default time zone (aka the "local" time zone) unless otherwise specified, and the parsed value is converted to UTC for storage in a Date object.
Formatting a Date value to string will always use the time zone of the SimpleDateFormat.
Cleaning up the code in the question to not use Calendar, since that just obfuscates the issue, and commenting it to show what is going on, will answer your question of "point out what am I doing wrong in coding or conceptually":
Date now = new Date();
// Format the date in the local time zone
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println("my inputTime:"+ sdf.format(now));
// Format the date in GMT time zone
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("gmt+0 converted time:"+ sdf.format(now));
// Format the date in GMT time zone (again), since the time ** ERROR MIGHT **
// zone of the formatter is still set to GMT ** BE HERE **
String standdardTimeStr = sdf.format(now);
// Parse the GMT date string as-if it is in local time zone ** OR MAYBE HERE **
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date date = sdf2.parse(standdardTimeStr); // Date value here is wrong
// Format the bad date value back to string in the same time
// zone, which means you get GMT time back, even though that
// is not the value of the `date` variable
System.out.println("standard input time:"+ sdf2.format(date));
// Do it again, same result, because the time zone is changed ** ERROR HERE **
// on the wrong formatter object
sdf.setTimeZone(TimeZone.getTimeZone("GMT+6")); //or Asia/Dhaka
System.out.println("gmt+6 convertedtime:"+ sdf2.format(date));
You are missing to take the string representation of time to convert it back to local. The modified code below will give an idea on the same:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class TimeZoneExample {
public static void main(String[] args) throws ParseException {
Calendar cal = Calendar.getInstance();
final Date currentTime = cal.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
String timeInCurrentTimeZone = sdf.format(currentTime);
System.out.println("Time in current time zone: " + timeInCurrentTimeZone);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String timeInGMT = sdf.format(currentTime);
System.out.println("Time in GMT: " + timeInGMT);
// Now, take this time in GMT and parse the string -- this is the key, we want to work with the time which got
// displayed not the internal representation and that's why we will get the time from string!
Date parsedTime = sdf.parse(timeInGMT);
String parsedString = sdf.format(parsedTime);
System.out.println("(GMT) Time in Parsed String: " + parsedString); // here it will show up it in GMT as sdf is still set to GMT
// Change the zone for sdf
sdf.setTimeZone(TimeZone.getTimeZone("GMT+6")); // or Asia/Dhaka
System.out.println("(Local) Time in Parsed String: " + sdf.format(parsedTime)); // here it you will see the zone difference
}
}
Note: You will get better picture if you take fixed time instead of current time.

Time String to time representation Java

I have a string like this 210115 I want to represent it as 21:01:15 any ideas?.
I tried using Gregorian calendar but it adds date to it which I don't want
SimpleDateFormat sdf = new SimpleDateFormat("HHmmss");
Date date = new Date();
try{
date = sdf.parse("210115");
}
catch(Exception e){
}
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(date);
System.out.print(calendar.getTime());
Output is Thu Jan 01 21:01:15 UTC 1970 but what I want is just 21:01:15
Thanks.
To output a formatted date, you use another SimpleDateFormat object with a pattern with the format you want.
In this case, it sounds like you might want to use something like
SimpleDateFormat outputFormat = new SimpleDateFormat("HH:mm:ss");
System.out.println( outputFormat.format(date) );
So what you want is just a time, without time zone. I would recommend using the LocalTime class, which is exactly that, instead of the Date class.
LocalTime time = LocalTime.parse("210115", DateTimeFormatter.ofPattern("HHmmss"));
If u r getting the date string in "210115" this format and you want it in "21:01:15" format then why are you using date format.
Simply do string operation as:
String time="210115";
String newtime=time.substring(0,2)+":"+time.substring(2,4)+":"+time.substring(4,6);
System.out.println(newtime);
you will get the required format.21:01:15

Setting default year in Joda Time

I am currently using the joda dateTime Api in my application. I am using the following code to parse multiple formats of dates into one single format. I am having trouble though when the format does not have a year. currently it sets the year as "2000".
Is there a way to set the year to a default if it is missing?
private static final DateTimeParser[] parsers = {
DateTimeFormat.forPattern("dd/MMM/yyyy:HH:mm:ss Z").getParser(),
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").getParser(),
DateTimeFormat.forPattern("[dd/MMM/yyyy:HH:mm:ss Z]").getParser(),
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").getParser(),
DateTimeFormat.forPattern("MMM-dd HH:mm:ss,SSS").getParser()
};
public static DateTime ConvertDate(String timestamp) {
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(null, parsers).toFormatter();
DateTime date = formatter.parseDateTime(timestamp);
return date;
}
example:
Mar-07 13:59:13,219
becomes
2000-03-07T12:59:13.219-07:00
what I want :
example:
Mar-07 13:59:13,219
becomes
(currentyear)-03-07T12:59:13.219-07:00
You can use withDefaultYear():
public static DateTime convertDate(String timestamp) {
int stdYear = 1970; // example for new default year
DateTimeFormatter formatter =
new DateTimeFormatterBuilder().append(null, parsers).toFormatter()
.withDefaultYear(stdYear);
return formatter.parseDateTime(timestamp);
}
Since Joda 2.0 the default year is 2000 so that Feb 29 could be parsed correctly, check this.
Not sure if you can change that (check this with pivotYear), but as a bypass solution I would add current year to my timestamp if there wasn't any.

Format a Date object with DateFormat in Java

I'm trying to learn about Date objects and the DateFormat class and I keep getting an error in the examples I'm trying to do. The goal is to get a due date by adding 30 days to a pretend invoice date, and then to format that due date. The dueDate method, I believe, is correct, but I'm having trouble formatting it properly.
Here is the first thing I have that takes the invoice date and adds 30 days to it.
public Date getDueDate()
{
Calendar cal = new GregorianCalendar();
cal.setTime(getInvoiceDate());
cal.add(Calendar.DATE, 30);
Date dueDate = cal.getTime();
return dueDate;
}
The next part is where I'm having the trouble, as it keeps telling me it expects a Date object but is receiving a String and I'm not sure why, as I'm supplying a Date object.
public Date getFormattedDueDate()
{
Date dueDate = getDueDate();
DateFormat shortDate = DateFormat.getDateInstance(DateFormat.SHORT);
return shortDate.format(dueDate);
}
Can anyone help me figure out why it's telling me that my supplied variable (dueDate) is a String when it's coded as a Date object?
format(Date date) Formats a Date into a date/time String.
Shamse is right
shortDate.format(dueDate);
returns a String, you can easly fix this changing your return type
public String getFormattedDueDate()
{
Date dueDate = getDueDate();
DateFormat shortDate = DateFormat.getDateInstance(DateFormat.SHORT);
return shortDate.format(dueDate);
}
The answer by Shamse is correct.
For the heck of it, here's the same kind of code but:
Written using the third-party library, Joda-Time 2.3
Care taken with time zones. Depending on default time zones is risky.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
java.util.Date date = new Date(); // = getInvoiceDate();
org.joda.time.DateTime invoiceStoredDateTime = new org.joda.time.DateTime( date );
// Set to desired time zone. Ideally that invoice date was stored in UTC.
// Time Zone list: http://joda-time.sourceforge.net/timezones.html
org.joda.time.DateTimeZone denverTimeZone = org.joda.time.DateTimeZone.forID( "America/Denver" );
org.joda.time.DateTime invoiceZonedDateTime = invoiceStoredDateTime.toDateTime( denverTimeZone );
// Call method .withTimeAtStartOfDay() to set the time component to first moment of the day.
org.joda.time.DateTime dueDateInThirtyDays = invoiceZonedDateTime.plusDays( 30 ).withTimeAtStartOfDay();
org.joda.time.DateTime dueDateInOneMonth = invoiceZonedDateTime.plusMonths( 1 ).withTimeAtStartOfDay(); // Smart month calculation, aiming at same day number of month.
// Style – Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full. First for date, second for time.
// A date or time may be omitted by specifying a style character '-'.
String dueDateAsString = org.joda.time.format.DateTimeFormat.forStyle("S-").withLocale( Locale.US ).print( dueDateInThirtyDays );
org.joda.time.DateTime dueDateInUtcForStorage = dueDateInThirtyDays.toDateTime( org.joda.time.DateTimeZone.UTC );
Show values on the console:
System.out.println( "date: " + date );
System.out.println( "invoiceZonedDateTime: " + invoiceZonedDateTime );
System.out.println( "dueDateInThirtyDays: " + dueDateInThirtyDays );
System.out.println( "dueDateInOneMonth: " + dueDateInOneMonth );
System.out.println( "dueDateAsString: " + dueDateAsString );
System.out.println( "dueDateInUtcForStorage: " + dueDateInUtcForStorage );
When run…
date: Thu Nov 28 13:39:05 PST 2013
invoiceZonedDateTime: 2013-11-28T14:39:05.125-07:00
dueDateInThirtyDays: 2013-12-28T00:00:00.000-07:00
dueDateInOneMonth: 2013-12-28T00:00:00.000-07:00
dueDateAsString: 12/28/13
dueDateInUtcForStorage: 2013-12-28T07:00:00.000Z

String Date Java

// Im new to java programming
I have a String object that represents a date/time in this format : "2013-06-09 14:20:00" (yyyy-MM-dd HH:mm:ss)
I want to convert it to a Date object so i can perform calculations on it but im confused on how to do this.
I tried :
String string = "2013-06-09 14:20:00";
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(string);
System.out.println(date);
//Prints Mon Dec 31 00:00:00 GMT 2012
Any help appreciated
Ok so I have now updated my code to as follows i'm getting the correct date/time now when I print the date but is this the correct implementation :
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = "2013-06-09 14:20:00";
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(string);
System.out.println(dateFormat.format(date));
//prints 2013-06-09 14:20:00
Thx to everyone that's answered/commented thus far
The format is wrong. Use this instead:
"yyyy-dd-MM HH:mm:ss"
Indeed your last program version is ok, except you don't need to declare the SimpleDateFormat twice. Simply:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = "2013-06-09 14:20:00";
Date date = dateFormat.parse(string);
System.out.println(dateFormat.format(date));
String string = "2013-06-09 14:20:00";
and the DATE object format is "yyyy-dd-MM HH:mm:ss"
You can get Date,Day,month and many more by using Date object which is present in
java.util.Date package , like as follows.
Date d = new Date(string);
This will call constructor of Date object for which you are passing 'string' variable which contains date.
d.getDay(); // retrieve day on that particular day
d.getDate(); // retrieve Date
and many more are avaiable like this.
Using java.util.Date
The answer by zzKozak is correct. Well, almost correct. The example code omits required exception handling. Like this…
java.text.DateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String string = "2013-06-09 14:20:00";
Date date = null;
try {
date = dateFormat.parse(string);
} catch ( ParseException e ) {
e.printStackTrace();
}
System.out.println("date: " + dateFormat.format(date));
Don't Use java.util.Date!
Avoid using java.util.Date & Calendar classes bundled with Java. They are notoriously bad in both design and implementation.
Instead use a competent date-time library. In Java that means either:
The third-party open-source Joda-Time
In the forthcoming Java 8, the new java.time.* classes defined by JSR 310 and inspired by Joda-Time.
Time Zone
Your question and code fail to address the issue of time zones. If you ignore time zones, you'll get defaults. That may cause unexpected behaviors when deployed in production. Better practice is to always specify a time zone.
Formatter
If you replace a space with a 'T' per the standard ISO 8601 format, then you can conveniently feed that string directly to a constructor of a Joda-Time DateTime instance.
If you must use that string as-is, then define a formatter to specify that format. You can find many examples of that here on StackOverflow.com.
Example Code
Here is some example code using Joda-Time 2.3, running in Java 7.
I arbitrarily chose a time zone of Montréal.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
// Specify a time zone rather than rely on default.
// Necessary to handle Daylight Saving Time (DST) and other anomalies.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTime = new DateTime( "2013-06-09T14:20:00", timeZone ); // Or pass DateTimeZone.UTC as time zone for UTC/GMT.
System.out.println( "dateTime: " + dateTime );
When run…
dateTime: 2013-06-09T14:20:00.000-04:00

Categories