Converting timezone for date faster using java - java

I have written this method for converting a date time zone. How do i reduce the execution time of this method further.
public static Timestamp convertTimeZone(final Timestamp fromDate, final TimeZone fromTZ, final TimeZone toTZ ){
Long timeInDate = fromDate.getTime() ;
int fromOffset = fromTZ.getOffset(timeInDate);
int toOffset = toTZ.getOffset(timeInDate);
Timestamp dateStamp = new Timestamp(fromDate.getTime());
if (fromOffset >= 0){
int diff = 0;
if (toOffset > 0){
diff = (fromOffset - toOffset);
} else {
diff = (fromOffset + Math.abs(toOffset));
}
long date = fromDate.getTime() - diff;
dateStamp.setTime(date);
} else {
int diff = 0;
if (toOffset > 0){
diff = (Math.abs( fromOffset) + toOffset);
} else {
diff = (Math.abs( fromOffset) - Math.abs(toOffset));
}
long date = fromDate.getTime() + diff;
dateStamp.setTime(date);
}
return dateStamp;
}

With joda-time it may look like this:
DateTime dt = new DateTime(DateTimeZone.forID("GMT"));
System.out.println(dt); // 5 am
dt = dt.withZone(DateTimeZone.forID("EET"));
System.out.println(dt); // 8 am
Note that Timestamp has no notion of Timezone so it is not suitable for representing it.
Your solution will have a good running time, since it's O(1). It's harder to read though.

You could store your date in a Calendar object to begin with. Showing it in different time zone formats will be a matter of configuration that you apply to a SimpleDateFormat.
Technically a Date is the same in all time zones (it's internal value is the same). Applying the concept of timezones allows date formatters to adjust offsets for display. In other words, a Date that represents 17:00 in London time is equal to a Date that represents 12:00 in New York. Displaying it in the GMT vs. the EST time zones can be a function of date formatters.

It's not quite an answer, but I recommend always store timestamp in database as UTC time instead of local time. And display it for different timezones only on presentation layer setting DateFormat.setTimeZone()

Related

Time offset between two dates

I have two timestamps and a localized date that I use to find the timezone offset and add it to these dates. How can I calculate the time offset between dates simpler? My method doesn't work with negative values (if (tsOffset.toSecondOfDay() > 0 always true).
fun parseDateTime(startTs: Long, endTs: Long, localizedDateTime: String): Pair<String, String> {
val dateUtcStart = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTs), ZoneOffset.UTC)
val dateUtcEnd = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTs), ZoneOffset.UTC)
val formatter = DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseDefaulting(ChronoField.YEAR_OF_ERA, dateUtcStart.year.toLong())
.append(DateTimeFormatter.ofPattern("E dd MMM hh:mm a"))
.toFormatter(Locale.ENGLISH)
val localDateTime = LocalDateTime.parse(localizedDateTime, formatter)
val localTs = Timestamp.valueOf(localDateTime).time
val tsOffset = LocalTime.ofInstant(Instant.ofEpochMilli(localTs - startTs), ZoneOffset.systemDefault())
val tzString = if (tsOffset.toSecondOfDay() > 0) "+$tsOffset" else tsOffset.toString()
val startDate = dateUtcStart.toString() + tzString
val endDate = dateUtcEnd.toString() + tzString
return Pair(startDate, endDate)
}
#Test
fun parseDateTime() {
val pair1 = parseDateTime(1626998400000, 1627005600000, "Fri 23 Jul 10:30 am")
val pair2 = parseDateTime(1626998400000, 1627005600000, "Thu 22 Jul 11:30 pm")
// pass
assertEquals("2021-07-23T00:00+10:30", pair1.first)
assertEquals("2021-07-23T02:00+10:30", pair1.second)
// fails
assertEquals("2021-07-23T00:00-00:30", pair2.first)
assertEquals("2021-07-23T02:00-00:30", pair2.second)
}
Also I tried
val dur = Duration.between(dateUtcStart, localDateTime)
But don't sure how to convert it in the string or add to the dates properly.
Here startTs - start of an event timestamp. endTs - end of this event timestamp. localizedDateTime is used to show the start time in the actual time zone (real city) while timestamps show time in UTC. I need to extract this timezone from localizedDateTime and add it to start and end string dateTimes (start = "2021-07-23T00:00+10:30", end = "2021-07-23T02:00+10:30" for startTs = 1626998400000 and endTs = 1627005600000 accordingly).
It’s no simpler than your code, on the contrary, but it fixes a couple of issues that you had.
Disclaimer: I haven’t got your Pair class and I cannot write nor run Kotlin. So I am printing the resulting strings from withint the method, which you will have to change for your purpose. And you will have to hand translate my Java.
private static void parseDateTime(long startTs, long endTs, String localizedDateTime) {
// startTs and localizedDateTime are both representations of the event start time.
// Use this information to obtain the UTC offset of the local time.
Instant startInstant = Instant.ofEpochMilli(startTs);
OffsetDateTime startUtc = startInstant.atOffset(ZoneOffset.UTC);
// Corner case: the local year may be different from the UTC year if the event is close to New Year.
// Check whether this is the case. First get the UTC month and the local month.
Month utcMonth = startUtc.getMonth();
DateTimeFormatter baseSyntaxFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("E dd MMM hh:mm a"))
.toFormatter(Locale.ENGLISH);
Month localMonth = baseSyntaxFormatter.parse(localizedDateTime, Month::from);
int utcYear = startUtc.getYear();
int localYear;
if (utcMonth.equals(Month.DECEMBER) && localMonth.equals(Month.JANUARY)) {
// Local date is in the following year
localYear = utcYear + 1;
} else if (utcMonth.equals(Month.JANUARY) && localMonth.equals(Month.DECEMBER)) {
localYear = utcYear - 1;
} else {
localYear = utcYear;
}
DateTimeFormatter finalFormatter = new DateTimeFormatterBuilder()
.append(baseSyntaxFormatter)
.parseDefaulting(ChronoField.YEAR_OF_ERA, localYear)
.toFormatter(Locale.ENGLISH);
LocalDateTime startLocal = LocalDateTime.parse(localizedDateTime, finalFormatter);
// Now calculate offset
Duration durationOfOffset = Duration.between(startUtc.toLocalDateTime(), startLocal);
ZoneOffset offset = ZoneOffset.ofTotalSeconds(Math.toIntExact(durationOfOffset.getSeconds()));
String startString = startLocal.atOffset(offset).toString();
// Calculate end date and time
String endString = Instant.ofEpochMilli(endTs)
.atOffset(offset)
.toString();
System.out.format("%s - %s%n", startString, endString);
}
Let’s try it with your example data:
parseDateTime(1_626_998_400_000L, 1_627_005_600_000L, "Fri 23 Jul 10:30 am");
parseDateTime(1_626_998_400_000L, 1_627_005_600_000L, "Thu 22 Jul 11:30 pm");
Output:
2021-07-23T10:30+10:30 - 2021-07-23T12:30+10:30
2021-07-22T23:30-00:30 - 2021-07-23T01:30-00:30
You notice that the local start times are now 10:30 and 23:30 as in your input strings, which I believe corrects an error that you had.
Let’s also try an example that bridges New Year:
Instant start = Instant.parse("2021-01-01T00:00:00Z");
parseDateTime(start.toEpochMilli(),
start.plus(2, ChronoUnit.HOURS).toEpochMilli(),
"Thu 31 Dec 10:30 pm");
2020-12-31T22:30-01:30 - 2021-01-01T00:30-01:30
I have used basically the same way of calculating the offset that you present in your own answer.
Issues with your code
First, as I said, the times that your unit test asserts do not agree with the times in your input. For the required output you have taken the UTC time of day and combined with the local offset, which gives a different point in time. A UTC offset is always used with a time of day at that offset (for UTC time of day one would use either offset Z or +00:00).
Consider having your method return a Pair<OffsetDateTime, OffsetDateTime>, not a Pair<String, String>. Strings are for presentation to the user and sometimes for data exchange. Inside your program you should use proper date-time objects, not strings.
As I said in the comments, New Year doesn’t happen at the same time in all time zones. So the year that you get from dateUtcStart.year.toLong() needs not be the year that was assumed in the string from a different time zone. My code takes this into account.
Don’t involve the Timestamp class. It’s poorly designed and long outdated. All it gives you is an extra conversion, hence extra complication.
Your basic problem was using a LocalTime for a duration that might be positive or negative. A LocalTime is for a time of day, not for an amount of time. Your own solution already got rid of this problem.
This is wrong:
val startDate = dateUtcStart.toString() + tzString
First, you should not want to use string manipulation for date and time math. The classes from java.time that you are using produce the string that you need more easily and with less risk of errors. Second, you have indeed got an error here: you are appending the calculated offset to a string that is in UTC, that is, assumes offset 0 (or Z). This was why you were in fact able to produce the incorrect results that your unit test expected.
I got an answer on the Kotlin forum:
val duration = Duration.between(dateUtcStart, localDateTime)
val offset = ZoneOffset.ofTotalSeconds(duration.seconds.toInt())
val startDate = dateUtcStart.atOffset(offset).toString()
val endDate = dateUtcEnd.atOffset(offset).toString()

Get current time and check if time has passed a certain period

this code below gets the current time and timezone of the area
Date date = new Date();
DateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getDefault());
System.out.println("Time: " + df.format(date));
right now its 1:01 pm (at the time of typing)
what i need help doing is implementing a feature in the code that checks if the current time has passed, for example 1:00PM
but I have no idea where to even start, can you help me out?
Use the Java 8+ Time API class LocalTime:
LocalTime refTime = LocalTime.of(13, 0); // 1:00 PM
// Check if now > refTime, in default time zone
LocalTime now = LocalTime.now();
if (now.isAfter(refTime)) {
// passed
}
// Check if now >= refTime, in pacific time zone
LocalTime now = LocalTime.now(ZoneId.of("America/Los_Angeles"))
if (now.compareTo(refTime) >= 0) {
// passed
}
I see it has already answered with Time, but as a teaching point, if you really wanted to use Date, you could have done something like this:
public static void main(String[] args) {
Date date = new Date();
DateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getDefault());
System.out.println("Time: " + df.format(date));
//If you print the date you'll see how it is formatted
//System.out.println(date.toString());
//So you can just split the string and use the segment you want
String[] fullDate = date.toString().split(" ");
String compareAgainstTime = "01:00PM";
System.out.println(isPastTime(fullDate[3],compareAgainstTime));
}
public static boolean isPastTime(String currentTime, String comparedTime) {
//We need to make the comparison time into the same format as the current time: 24H instead of 12H:
//then we'll just convert the time into only minutes to that we can more easily compare;
int comparedHour = comparedTime[-2].equals("AM") ? String.valueOf(comparedTime[0:2]) : String.valueOf(comparedTime[0:2] + 12 );
int comparedMin = String.valueOf(comparedTime[3:5]);
int comparedT = comparedHour*60 + comparedMin;
//obviously currentTime is alredy the correct format; just need to convert to minutes
int currentHour = String.valueOf(currentTime[0:2]);
int currentMin = String.valueOf(currentTime[3:5]);
int currentT = currentHour*60 + currentMin;
return (currentT > comparedT);
}
It's a bit messier, having to muddy into the Strings and whatnot, but it is possible. You would also have to be careful the zero-pad the comparedTime or just check for that in the function

How to compare Calendar's time to java.sql.Time object?

I want to know whether the Time values of a Calendar object equal the value of a java.sql.Time object.
E.g
Calendar c; //c.getTime().toString() == "Sat Jan 07 09:00:00 GMT 2012"
Time t; //d.toString() == "09:00:00";
I tried
t.equals(c.getTime())
But because the Calendar has Date information the expression is false.
What would be the best way the compare the two?
Edit:
The Time object is retrieve though Hibernate and come with no date information.
The Calendar object is create by
Calendar c= Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 9);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
The way you use is perfectly fine. The goal is unclear, though. Why do you want c to be equal to d?
Additionally, there's no way to have d.toString() == "09:00:00" — Date always have, well, the date included.
What's more important, though, is that Date has no timezone information (well, it used to have, but you're discouraged to touch this part of Date), so you cannot tell 09:00 UTC from 10:00 BST—that is, unless you specify the timezone. You can get the timezone from Calendar c, and it sort of explains what you need to do:
Create a Calendar from your date
Copy timezone from the calendar you already use
Compare the Calendar fields which are of interest for you. I suppose that will be hour, minute, second, and, perhaps, millisecond.
Update: now that you've mentioned it's actually java.sql.Time, I'm worried. The problem is,
SQL servers usually store time as a structure containing hours, minutes, seconds, etc. That is, there's an implied timezone (the SQL Server timezone)
java.sql.Time stores time as milliseconds since "zero epoch" value of January 1, 1970. The date part is usually stripped to January 1, 1970 — but this class does not contain timezone information. (Well, again, it sort of does, but it's deprecated.)
Calendar has an explicitly set timezone
What it means in practice is, that the time from the server gets converted into milliseconds using system default timezone, then you read this value and compare it with a Calendar with its own timezone.
If it sounds confusing and fragile, that's because it is. So basically you have three timezones:
SQL Server TZ
JVM's default TZ
Calendar's TZ
All three must be the same so that any comparison would make any sense.
You can use Date, Calendar, GregorianCalendar,SimpleDateFormat` etc classes to deal with date-time in Java. Let's see some examples.
SimpleDateFormat dayFormat = new SimpleDateFormat("D");
int _currentDay = Integer.parseInt(dayFormat.format(new Date(System.currentTimeMillis())));
SimpleDateFormat monthFormat = new SimpleDateFormat("M");
int _currentMonth = Integer.parseInt(monthFormat.format(new Date(System.currentTimeMillis())));
SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy");
int _currentYear = Integer.parseInt(yearFormat.format(new Date(System.currentTimeMillis())));
System.out.println(_currentDay+"/"+_currentMonth+"/"+_currentYear);
Would display the current date based on the current millisecond.
String toDate = "07/1/2012";
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
Calendar currentDateCal = Calendar.getInstance();
// Zero out the hour, minute, second, and millisecond.
currentDateCal.set(Calendar.HOUR_OF_DAY, 0);
currentDateCal.set(Calendar.MINUTE, 0);
currentDateCal.set(Calendar.SECOND, 0);
currentDateCal.set(Calendar.MILLISECOND, 0);
Date currentDate = currentDateCal.getTime();
Date toDt;
try
{
toDt = df.parse(toDate);
}
catch (ParseException e)
{
toDt = null;
System.out.println(e.getMessage());
}
if (currentDate.equals(toDt))
{
System.out.println(currentDate); // Displays the current date.
//Rest of the stuff.
}
String toDate = "07/12/2012";
try
{
if (new SimpleDateFormat("MM/dd/yyyy").parse(toDate).getTime() / (1000 * 60 * 60 * 24) >= System.currentTimeMillis() / (1000 * 60 * 60 * 24))
{
System.out.println("True");
}
else
{
System.out.println("Untrue");
}
}
catch(ParseException ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
String toDateAsString = "07/12/2012";
Date toDate=null;
try
{
toDate = new SimpleDateFormat("MM/dd/yyyy").parse(toDateAsString);
}
catch (ParseException ex)
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
long toDateAsTimestamp = toDate.getTime();
long currentTimestamp = System.currentTimeMillis();
long getRidOfTime = 1000 * 60 * 60 * 24;
long toDateAsTimestampWithoutTime = toDateAsTimestamp / getRidOfTime;
long currentTimestampWithoutTime = currentTimestamp / getRidOfTime;
if (toDateAsTimestampWithoutTime >= currentTimestampWithoutTime)
{
System.out.println("True");
}
else
{
System.out.println("False");
}
The JodaTime's variant:
String toDateAsString = "07/01/2012";
DateTime toDate = DateTimeFormat.forPattern("MM/d/yyyy").parseDateTime(toDateAsString);
DateTime now = new DateTime();
if (!toDate.toLocalDate().isBefore(now.toLocalDate()))
{
System.out.println("True");
}
else
{
System.out.println("False");
}
why don't you compare the time in milliseconds?
Date d;
Calendar c;
System.out.println(d.getTime() == c.getTimeInMillis());
Since, you tagged this Question with DateTime, i assume you use Joda already
...
//Initialize Calendar and Date Object
DateTime d1 = new DateTime(c.getTime());
DateTime d2 = new DateTime(d.getTime());
// Convert d1 and d2 to LocalDate say ld1 and ld2 since, Java Date defaults to GMT
ld1.compareTo(ld2);
?
I had to do this today and the answers in this post helped my solve my problem. I know all my timezones are the same like the OPs. And I don't have the liberty to use Joda time in my legacy code so for the benefit of others who have the same conditions, here is how I did it with vanilla Java.
Methodology:
java.sql.Time has a getTime() due to inheritance from
java.util.Date. Using this method, one can create a
java.util.Date object that represents just the time portion since
Java epoch.
For comparison, one must convert the desired java.util.Calendar
object to produce a java.util.Date object that represents another
time since Java epoch.
Since the date parts are now equivalent, any comparison between the 2
objects would only compare the time parts producing the desired result.
Without further adieu, here is the code:
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class Test {
/**
* Method to convert a calendar object to java's epoch date
* keeping only the time information
*/
public static Date toEpochDate(Calendar calendar) {
return new Date(Time.valueOf(new SimpleDateFormat("HH:mm:ss").format(calendar.getTime())).getTime());
}
public static void main(String[] args) {
// create any calendar object
Calendar someTime = Calendar.getInstance();
someTime.set(Calendar.HOUR_OF_DAY, 17);
someTime.set(Calendar.MINUTE, 0);
someTime.set(Calendar.SECOND, 0);
// convert it to java epoch date
Date someDate = toEpochDate(someTime);
// create a date object from java.sql.Time
Date fromSqlTime = new Date(Time.valueOf("17:00:00").getTime());
// now do the comparison
System.out.println("Some Date: " + someDate.toString());
System.out.println("Sql Time: " + fromSqlTime.toString());
System.out.println("Are they equal? " + someDate.equals(fromSqlTime));
}
}
The above produces the following output:
Some Date: Thu Jan 01 17:00:00 EST 1970
Sql Time: Thu Jan 01 17:00:00 EST 1970
Are they equal? true
Using the above methodology, and by changing .equals() to .before() or .after(), various time comparison convenience methods can be created.

What is the equivalent of getTime(), which is a method in Date, in joda.time.LocalDate?

I was doing a simple calculation to get the difference between two dates. If I was using a Date class I can do like this:
Date d1 = new GregorianCalendar(2000, 11, 31, 23, 59).getTime();
/** Today's date */
Date today = new Date();
// Get msec from each, and subtract.
long diff = today.getTime() - d1.getTime();
System.out.println("The 21st century (up to " + today + ") is "
+ (diff / (1000 * 60 * 60 * 24)) + " days old.");
}
But I couldn't find a method like getTime() in Local date. Is there any way so I can easily get what I am trying to achieve?
I even tried to change my LocalDate object to a temporary date object like this:
LocalDate date=new LocalDate();
Date d=date.toDate();
but the method toDate() isnt working . i.e it says it is not recognized method.(so compile time error) but from what I can see it is in the Documentation
Thank you for your time and of course happy Thanksgiving.
Days.daysBetween() is the answer.
LocalDate now = new LocalDate();
LocalDate past = now.minusDays(300);
int days = Days.daysBetween(past,now).getDays();
Never convert a LocalDate to a Java Date (two completey different beasts) if you are just dealing with dates. A Jodatime Localdate is a true "Calendar date", i.e. , a tuple of {day,month,year} (together with a Gregorian calendar specification), and has nothing to do with "physical time", with seconds, hours, etc. If you need to do dates arithmetic, stick with Localdate and you'll never need to worry about stupid bugs (timezones, DST, etc) which could arise if you dates arithmetic using java Dates.
Try something like this:
LocalDate date = new LocalDate();
Date utilDate = date.toDateTimeAtStartOfDay( timeZone ).toDate( );
or refer to this post
How to convert Joda LocalDate to java.util.Date?
I tested this sample code to find out the difference in days, you can find the difference as per your needs.
Please see http://joda-time.sourceforge.net/key_period.html
LocalDate currentDate = new LocalDate();
LocalDate previousDate = currentDate.minusDays(1);
System.out.println(currentDate);
System.out.println(previousDate);
Period periodDifference = new Period(currentDate, previousDate, PeriodType.days());
System.out.println(periodDifference);
private long diff(Calendar c1, Calendar c2) {
long d1 = c1.getTimeInMillis();
long d2 = c2.getTimeInMillis();
return ((d2 - d1) / (60*60*24*1000));
}
Have not found any equivalents for LocalDate as they are not exact.
But there are several equivalents for LocalDateTime:
LocalDateTime localDateTime = LocalDateTime.now();
long longValue = ZonedDateTime.of(localDateTime, ZoneId.systemDefault()).toInstant().toEpochMilli();
or
long longValue = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
or
long longValue = localDateTime.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli();
or
long longValue = Timestamp.valueOf(localDateTime).getTime();

Changing timezone without changing time in Java

I'm receiving a datetime from a SOAP webservice without timzone information. Hence, the Axis deserializer assumes UTC. However, the datetime really is in Sydney time. I've solved the problem by substracting the timezone offset:
Calendar trade_date = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
long millis = trade_date.getTimeInMillis() - est_tz.getRawOffset();
trade_date.setTimeZone( est_tz );
trade_date.setTimeInMillis( millis );
However, I'm not sure if this solution also takes daylight saving into account. I think it should, because all operations are on UTC time. Any experiences with manipulating time in Java? Better ideas on how to solve this problem?
I pity the fool who has to do dates in Java.
What you have done will almost certainly go wrong around the daylight savings transitions. The best way to to it is probably to create a new Calendar object, set the Timezone on it, and then set all of the fields individually, so year, month, day, hour, minute, second, getting the values from the Date object.
Edit:
To keep the everyone happy, you should probably do this:
Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar sydneyTime = Calendar.getInstance(TimeZone.getTimeZone("Australia/Sydney");
utcTime.setTime(trade_date);
for (int i = 0; i < Calendar.FIELD_COUNT; i++) {
sydneyTime.set(i, utcTime.get(i));
}
Then you won't be using any deprecated methods.
I want to thank the person for responce 6. This was a great start for me and an approach I did not consider. There are some addtional steps required to bring it to production code level. In particular observe the steps required for DST_OFFSET and ZONE_OFFSET. I want to share the solution I came up with.
This takes the time from the input Calendar object, copies it to the output time, sets the new time zone to the output. This is used when taking time literally from the database and setting the Time Zone without changing the time.
public static Calendar setNewTimeZoneCopyOldTime( Calendar inputTime,
TimeZone timeZone ) {
if( (inputTime == null) || (timeZone == null) ) { return( null ); }
Calendar outputTime = Calendar.getInstance( timeZone );
for( int i = 0; i < Calendar.FIELD_COUNT; i++ ) {
if( (i != Calendar.ZONE_OFFSET) && (i != Calendar.DST_OFFSET) ) {
outputTime.set(i, inputTime.get(i));
}
}
return( (Calendar) outputTime.clone() );
}
However, I'm not sure if this solution
also takes daylight saving into
account. I think it should, because
all operations are on UTC time.
Yes, you should take the daylight saving into account, since it affects the offset to UTC.
Any experiences with manipulating time in Java? Better ideas on how to solve this problem?
Joda-Time is a better time API. Maybe the following snippet could be of help :
DateTimeZone zone; // TODO : get zone
DateTime fixedTimestamp = new DateTime(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
JodaTime types are immutable which is also a benefit.
I normally do it this way
Calendar trade_date_utc = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
Calendar trade_date = Calendar.GetInstance(est_tz);
trade_date.setTimeInMillis( millis );
Are you getting an ISO 8601 style string from that messed-up Web Service? If so, the Joda-Time 2.3 library makes this very easy.
If you are getting an ISO 8601 string without any time zone offset, you pass a time zone object to the DateTime constructor.
DateTimeZone timeZone = DateTimeZone.forID( "Australia/Sydney" );
String input = "2014-01-02T03:00:00"; // Note the lack of time zone offset at end.
DateTime dateTime = new DateTime( input, timeZone );
Dump to console…
System.out.println( "dateTime: " + dateTime );
When run…
dateTime: 2014-01-02T03:00:00.000+11:00
#Test
public void tzTest() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");
TimeZone tz1 = TimeZone.getTimeZone("Europe/Moscow");
Calendar cal1 = Calendar.getInstance(tz1);
long l1 = cal1.getTimeInMillis();
df.setTimeZone(tz1);
System.out.println(df.format(cal1.getTime()));
System.out.println(l1);
TimeZone tz2 = TimeZone.getTimeZone("Africa/Douala");
Calendar cal2 = Calendar.getInstance(tz2);
long l2 = l1 + tz1.getRawOffset() - tz2.getRawOffset();
cal2.setTimeInMillis(l2);
df.setTimeZone(tz2);
System.out.println(df.format(cal2.getTime()));
System.out.println(l2);
assertNotEquals(l2, l1);
}
Running CalendarTest
2016-06-30 19:09:16.522 +0300
1467302956522
2016-06-30 19:09:16.522 +0100
1467310156522
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.137 sec
I've decided to reparse the datetime string received with the correct time zone set. This should also consider daylight saving:
public class DateTest {
private static SimpleDateFormat soapdatetime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
/**
* #param args
*/
public static void main(String[] args) {
TimeZone oztz = TimeZone.getTimeZone("Australia/Sydney");
TimeZone gmtz = TimeZone.getTimeZone("GMT");
Calendar datetime = Calendar.getInstance( gmtz );
soapdatetime.setTimeZone( gmtz );
String soap_datetime = soapdatetime.format( datetime.getTime() );
System.out.println( soap_datetime );
soapdatetime.setTimeZone( oztz );
datetime.setTimeZone( oztz );
try {
datetime.setTime(
soapdatetime.parse( soap_datetime )
);
} catch (ParseException e) {
e.printStackTrace();
}
soapdatetime.setTimeZone( gmtz );
soap_datetime = soapdatetime.format( datetime.getTime() );
System.out.println( soap_datetime );
}
}

Categories