Lance
Lance

Reputation: 3213

Convert timezones in ColdFusion with Java but can't get new time

I have a simple script

<cfscript>
public string function convertTimeZone( 
    string  toTimeZone  = "America/New_York"
,   date    thisDate  = now()
){
    var azTimeZone = createObject("java", "java.util.TimeZone").getTimeZone(javaCast("string","US/Arizona"));
    var azCalendar = createObject("java", "java.util.GregorianCalendar" ).init(azTimeZone);

    azCalendar.set(
        javaCast( "int", year( arguments.thisDate ) ),
        javaCast( "int", (month( arguments.thisDate ) - 1) ),
        javaCast( "int", day( arguments.thisDate ) ),
        javaCast( "int", hour( arguments.thisDate ) ),
        javaCast( "int", minute( arguments.thisDate ) ),
        javaCast( "int", second( arguments.thisDate ) )
    );
    var newCal = azCalendar.clone();
    newCal.setTimeInMillis(azCalendar.getTimeInMillis());
    newCal.setTimeZone(javaCast("string",arguments.toTimeZone));


    writeOutput('AZ Cal');
    writeDump(azCalendar);
    writeDump(azCalendar.Timezone);
    writeDump(azCalendar.Time);
    writeDump(azCalendar.getTime());
    writeOutput('New Cal');
    writeDump(newCal);
    writeDump(newCal.Timezone);
    writeDump(newCal.Time);
    writeDump(newCal.getTime());

}

convertTimeZone();
</cfscript>

If you look at the output you will see that the new calendar contains the correct timezone and time but if I use getTime() it is not returning the correct value. I am sure that I have done something either in setting the time in the new calendar or maybe even the clone but I can't quite figure it out.

If I add writeDump(newCal.getTimezone()); to the list of dumps I do get "America/New_York"

enter image description here

Upvotes: 1

Views: 600

Answers (2)

Ageax
Ageax

Reputation: 1

Actually it doesn't contain the correct time. The presentation in the dump just makes it seem that way. WriteDump() must apply extra magic when displaying Calendar objects.

The date value does not change due to how newCal is created. Instead of cloning azCalendar, create a new instance and apply the azCalendar time with set(...). Then the date value will change. However I'm not sure it works as expected for arbitrary time zones, only the jvm default

Supposedly Java 8+ has improved date options, which are worth investigating. For earlier versions I have used the SimpleDateFormat trick. Create two formatters. One to parse the input using the original time zone. Another to format the output, using the desired time zone. Then convert the final string back into a date object with parseDateTime().

thisDate = now();
fromTimeZone = "America/Phoenix";
toTimeZone = "America/New_York";

dateMask = "yyyy-MM-dd HH:mm:ss";
timeZone = createObject("java", "java.util.TimeZone");

fromFormat = createObject("java", "java.text.SimpleDateFormat").init(dateMask);
fromFormat.setTimeZone(timeZone.getTimeZone(fromTimeZone));
// parse input as date string
dateString = dateTimeFormat(thisDate, "yyyy-MM-dd HH:nn:ss");
fromDate = fromFormat.parse(dateString); 

// format output as date string
toFormat = createObject("java", "java.text.SimpleDateFormat").init(dateMask);
toFormat.setTimeZone(timeZone.getTimeZone(toTimeZone));

// convert back into date
toDate = parseDateTime(toFormat.format(fromDate));
writeDump(toDate);

Upvotes: 0

Alex
Alex

Reputation: 7833

You can "trick" ColdFusion into using timezone adjusted date objects (since java.util.Date cannot be timezone aware).

<cfscript>

    srcDate = createDateTime(2017, 10, 07, 16, 33, 37);
    srcTZ   = "US/Arizona";

    dstTZ   = "America/New_York";

    TimeZone = createObject("java", "java.util.TimeZone");
    srcTZinfo = TimeZone.getTimeZone(srcTZ);
    dstTZinfo = TimeZone.getTimeZone(dstTZ);

    srcOffset = (srcTZinfo.getRawOffset() / 1000);
    dstOffset = (dstTZinfo.getRawOffset() / 1000);

    srcDSToffset = (srcTZinfo.getDSTSavings() / 1000);
    dstDSToffset = (dstTZinfo.getDSTSavings() / 1000);

    src2utc = dateAdd("s", -(srcOffset + srcDSToffset), srcDate);
    utc2dst = dateAdd("s",  (dstOffset + dstDSToffset), src2utc);

</cfscript>

<cfdump label="#srcTZ#" var="#srcDate#">
<cfdump label="#dstTZ#" var="#utc2dst#">

The snippet converts the source date object srcDate into a UTC date using the specified timezone srcTZ. The UTC date is then adjusted to the desired timezone dstTZ and the final date object put into utc2dst.

Upvotes: 1

Related Questions