What is the best/simplest way to format a date (milliseconds) to a string equivalent conforming to a specified timezone using python scripting?
The system.date.format() function does not appear to provide capability to specify the timezone you want the output to conform to.
I’m expecting that I am overlooking some simple build-in function.
I’m looking for a general answer but my specific use case is that I’m attempting to return the results of a system.tag.queryTagHistory request with added columns so I can return the block start/end dates formatted as either UTC time or a specified timezone (e.g. ‘US.Central’) or both. I can use Custom Tag History Aggregate functions to retrieve the block start/end dates (timestamps) as millisecond values.
You can construct a SimpleDateFormat object with your desired Locale, which will then use the default timezone from that locale for formatting. Locales can be obtained in a bunch of different ways, but the easiest might be LocaleUtils.parseLocale().
After calling system.tagQueryTagHistory, I convert the t_stamp column to a list.
Then I use map calling that function to convert them to the desired timezone.
Then I remove the t_stamp column from the original dataset, and merge in the updated column to the final dataset for use.
I have to do this since we do history queries using WEBDEV and people from all different timezones use it and it gathers data from locations all with different timezones as well.
I had also put in a suggestion for an additional parameter for queryTagHistory to be able to specify TZ for the returned dataset as well.
With the use of WEBDEV so prevalent this would be extremely helpful for companies using the gateway network with historian splitters and remote historians in different timezones.
With WebDev the TZ of the gateway it is running on is what is returned.
Can't do that. Datasets carry java.util.Date values or the subclass java.sql.Timestamp, neither of which carry a timezone. TZ has to be applied at the point where you convert to string.
@PGriffith thanks for your response. Forgive my potential ignorance here but as far as I know (and was able confirm with brief investigation) a locale is not directly relatable to a time zone, it just helps determine how string representations of time strings are to be interpreted/presented based on language standards. For example the java supported locales for all of the United stated is en-US and es-US (English or Spanish).
However, I am happy to be corrected if you could provide a code example of outputting a date (milliseconds) to a string conforming to the ‘US/Central’ time-zone.
Thanks.
@PGriffith, thanks that is exactly what I needed.
For practice/familiarization I converted it into two functions, one compact-ish, one with lots of debug info:
from java.util import TimeZone # https://docs.oracle.com/javase/8/docs/api/java/util/TimeZone.html
from java.text import SimpleDateFormat # https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
def date2String(paramDate, paramTimeZoneID=None, paramPattern=None):
# if the 'date' parameter is not the expected type ('java.util.date') then assume it is a date expressed as milliseconds and convert it
myDate = paramDate if str(type(paramDate)) == "<type 'java.util.Date'>" else system.date.fromMillis(paramDate)
# If the 'Pattern' parameter was provided then create a SimpleDateFormat object using that pattern, if not assume a detailed pattern
myPattern = paramPattern if (paramPattern is not None) else 'yyyy-MM-dd HH:mm:ss.SSSZZZ zzzz'
# Create a SimpleDateFormat object using the provided pattern
mySdf = SimpleDateFormat(myPattern)
# if the 'TimeZoneID' parameter was provided then adjust the SimpleDateFormat object's timezone, if not provided then leave at system default
myTimeZone = TimeZone.getTimeZone(paramTimeZoneID) if (paramTimeZoneID is not None) else mySdf.getTimeZone()
mySdf.setTimeZone(myTimeZone)
return mySdf.format(myDate)
def date2String_debug(paramDate, paramTimeZoneID=None, paramPattern=None, paramDebug=True):
if paramDebug:
sdf = SimpleDateFormat()
print '-- System Defaults ---'
print 'TimeZone ID: {} {}'.format(sdf.getTimeZone().getID(), type(sdf.getTimeZone().getID()))
print 'TimeZone Object: {} {}'.format(sdf.getTimeZone(), type(sdf.getTimeZone()))
print 'Pattern: {} {}'.format(sdf.toPattern(), type(sdf.toPattern()))
print 'Localized Pattern: {} {}'.format(sdf.toLocalizedPattern(), type(sdf.toLocalizedPattern()))
print 'Date String: {} {}'.format(sdf.format(dt), type(sdf.format(dt)))
print '\n-- Function Parameters (Raw) --'
print 'Date: {} {}'.format(paramDate, type(paramDate))
print 'TimeZone ID: {} {}'.format(paramTimeZoneID, type(paramTimeZoneID))
print 'Pattern: {} {}'.format(paramPattern, type(paramPattern))
sdf = None
#================================================================================
# Evaluate and apply function parameters
#================================================================================
# if the 'date' parameter is not the expected type ('java.util.date') then assume it is a date expressed as milliseconds and convert it
if str(type(paramDate)) == "<type 'java.util.Date'>":
myDate = paramDate
else:
myDate = system.date.fromMillis(paramDate)
# If the 'Pattern' parameter was provided then create a SimpleDateFormat object using that pattern, if not assume a detailed pattern
if (paramPattern is not None):
myPattern = paramPattern
else:
myPattern = 'yyyy-MM-dd HH:mm:ss.SSSZZZ zzzz'
# Create a SimpleDateFormat object using the provided pattern
mySdf = SimpleDateFormat(myPattern)
# if the 'TimeZoneID' parameter was provided then adjust the SimpleDateFormat object's timezone, if not provided then leave at system default
if (paramTimeZoneID is not None):
myTimeZone = TimeZone.getTimeZone(paramTimeZoneID)
else:
myTimeZone = mySdf.getTimeZone()
mySdf.setTimeZone(myTimeZone)
#================================================================================
# Create Result (Return Value)
#================================================================================
myResult = mySdf.format(myDate)
if paramDebug:
print '-- Function Parameters (Corrected) --'
print 'Date: {} {}'.format(myDate, type(myDate))
print 'TimeZone ID: {} {}'.format(myTimeZone.getID(), type(myTimeZone.getID()))
print 'Pattern: {} {}'.format(myPattern, type(myPattern))
print '-- Results ---'
print 'TimeZone ID: {} {}'.format(mySdf.getTimeZone().getID(), type(mySdf.getTimeZone().getID()))
print 'TimeZone Object: {} {}'.format(mySdf.getTimeZone(), type(mySdf.getTimeZone()))
print 'Pattern: {} {}'.format(mySdf.toPattern(), type(mySdf.toPattern()))
print 'Localized Pattern: {} {}'.format(mySdf.toLocalizedPattern(), type(mySdf.toLocalizedPattern()))
print 'Date String: {} {}'.format(mySdf.format(myDate), type(mySdf.format(myDate)))
return myResult
Example Usage:
now = system.date.now()
print 'A: {}'.format(date2String(paramDate=now))
print 'B: {}'.format(date2String(paramDate=now, paramTimeZoneID='US/Central'))
print 'C: {}'.format(date2String(paramDate=now, paramTimeZoneID='Canada/Mountain', paramPattern='EEEE LLLL dd y G K:m:s.S a zzzz'))
Example Results:
>>>
A: 2022-09-15 04:34:00.895+0000 Coordinated Universal Time
B: 2022-09-14 23:34:00.895-0500 Central Daylight Time
C: Wednesday September 14 2022 AD 10:34:0.895 PM Mountain Daylight Time