如何在Mirth中将本地日期转换为UTC?

4

我在Mirth中接收到一个本地日期时间字符串(201801011000),需要将其转换为UTC时间。我很快发现使用经典的js new Date() 不起作用。

例如:

var d = new Date("2018-01-01 10:00");
logger.info(d.toString());

当我执行某些操作时,出现了Invalid Date的错误提示。

经过进一步搜索,我发现可以使用以下方法来解决这个问题:

var d = DateUtil.getDate("yyyyMMddHHmm", "201801011000");

目前我遇到了困难。我不知道如何将此转换为UTC时间。现在假定本地服务器的时区已足够,但将来我还需要设置一个特定的非本地时区。

我尝试使用 Object.getOwnPropertyNames(d) 获取可用的方法,但这给了我一个有用的错误提示:TypeError: Expected argument of type object, but instead had type object

我还尝试查找DateUtil的Java文档并尝试其中的一些方法,但都没有起作用。

有人知道如何将日期字符串从本地时间转换为UTC吗?欢迎提供任何提示!


根据这些文档显示,看起来这是Java并且返回一个java.util.Date对象?如果是这样的话,那么这个问题已经被回答了很多次。我有点困惑,因为我不知道Mirth,而你提到了“classic js”-所以这是Java还是JavaScript? - Matt Johnson-Pint
1
我无法回答这个问题,但是作为背景 - 它有点两者兼备。 :) Mirth使用Rhino JavaScript引擎进行脚本编写,这意味着您编写JS代码并可以访问类路径中的所有Java类。在处理“这是JavaScript还是Java字符串对象?”等问题时可能会变得混乱和困惑。我只能假设,在日期和时间操作方面也是如此。 - Tarmo R
1
@TarmoR 听起来很糟糕 - bert
请注意,像 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 这样的旧日期时间类现在已经过时,被内置于 Java 8 及更高版本的 java.time 类所取代。可以参考 Oracle 的 教程(https://docs.oracle.com/javase/tutorial/datetime/TOC.html)。 - Basil Bourque
你应该使用Java8中提供的最新Java类进行转换。我已经为您的说明添加了我的答案。 - NullPointer
5个回答

4

在折腾了整整两天之后,我终于找到了一个解决方案。最终,我不得不涉及到Java,但由于无法导入任何Java依赖项,我不得不使用它们的直接类路径(例如:java.text.SimpleDateFormat)。

最终,以下是对我有效的方法:

var datestr = "201207011000".slice(0, 12);  // This is just a datetime string to test with

var formatter_hl7 = new java.text.SimpleDateFormat("yyyyMMddHHmm");
formatter_hl7.setTimeZone(java.util.TimeZone.getTimeZone("CET"));
var formatter_utc = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm");
formatter_utc.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));

var date_in_utc = formatter_utc.format(formatter_hl7.parse(date_str));

无论如何,我祝愿大家有一个美好的一天!

谁给这个点了踩?为什么要这样做?请解释一下有什么问题。 - kramer65
1
也许你的被踩是因为你正在使用可怕的旧日期时间类,这些类已经在多年前被优秀的java.time类所取代。 - Basil Bourque
仅提建议:不要使用旧的Java类进行转换。 - NullPointer

1

简而言之

  • 不要使用DateUtil,无论它是什么。(也许是Apache DateUtils库?)
  • 不要使用过时的糟糕日期时间类,如java.util.Date
  • 使用现代化业界领先的java.time类。

用于解析缺少偏移量的字符串的代码,然后将偏移量设置为UTC的零。

LocalDateTime                // Represents a date and a time-of-day but without any concept of time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline.
.parse( 
    "201801011000" ,
     DateTimeFormatter.ofPattern( "uuuuMMddHHmm" )
)  
.atOffset( ZoneOffset.UTC )  // Assign an offset-from-UTC. Do this only if you are CERTAIN this offset was originally intended for this input but was unfortunately omitted from the text. Returns an `OffsetDateTime`.
.toInstant()                 // Extract an `Instant` from the `OffsetDateTime`. Basically the same thing. But `Instant` is always in UTC by definition, so this type is more appropriate if your intention is to work only in UTC. On the other hand, `Instant` is a basic class, and `OffsetDateTime` is more flexible such as various formatting patterns when generating `String` object to represent its value.

使用java.time

Java的现代方法使用java.time类。这个领先行业的框架取代了非常麻烦的旧日期时间类,例如DateCalendarSimpleDateFormat

DateTimeFormatter

解析您的输入字符串。定义一个匹配的格式化模式。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmm" ) ;
String input = "201801011000" ;

LocalDateTime

将输入解析为LocalDateTime,因为它缺少时区或UTC偏移量指示器。

LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

缺少时区或偏移意味着这不代表一个时刻,也不是时间轴上的一个点。相反,这表示潜在的时刻在全球各地的时区范围内约为26-27小时。
如果您确定这个日期和时间是UTC中的一个时刻,请应用常量ZoneOffset.UTC来获取一个OffsetDateTime对象。
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

ZonedDateTime

您的问题比较模糊。听起来您可能知道特定的时区适用于此输入。如果是这样,请分配一个ZoneId以获取一个ZonedDateTime对象。

请注意,从UTC偏移量只是小时、分钟和秒数的简单数字。没有更多,也没有更少。相比之下,时区要复杂得多。时区是某个地区的人们使用的偏移量的过去、现在和未来变化的历史。

请指定一个正确的时区名称,格式为大陆/地区,例如America/MontrealAfrica/CasablancaPacific/Auckland。绝不要使用3-4个字母的缩写,如ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;

Instant

快速调整回UTC的方法是提取一个Instant对象。 Instant始终处于UTC。

Instant instan = zdt.toInstant() ;

ISO 8601

提示:在交换日期时间值的文本时,不要使用自定义格式,而是仅使用标准ISO 8601格式。标准格式实用、易于机器解析、易于跨文化人类阅读。

java.time类默认使用ISO 8601格式进行解析/生成字符串。 ZonedDateTime::toString方法明智地扩展了标准,以方括号中的区域名称作为附加信息。

Instant instant = Instant.parse( "2018-07-23T16:18:54Z" ) ;  // `Z` on the end means UTC, pronounced “Zulu”. 
String output = instant.toString() ;  // 2018-07-23T16:18:54Z

在你的字符串中始终包括偏移量和时区。暂时省略偏移量/时区就像省略价格的货币一样:你只剩下一个含糊不清、毫无意义的数字。实际上,这比没有还要糟糕,因为它可能引起各种混乱和错误。


关于java.time

java.time框架内置于Java 8及更高版本中。这些类替代了老旧的传统日期时间类,例如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

了解更多信息,请参见Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,也不需要java.sql.*类。

如何获取java.time类?

ThreeTen-Extra项目扩展了java.time的附加类。该项目是java.time可能未来添加的潜在试验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter更多


DateUtil 属于 Mirth 的 Java 版本。它的名字非常贴切:一个缺乏实用性的日期工具类。 - Mr.Z

0
在我的项目中有一个函数用于将日期字符串从本地时间转换为UTC,
function getDateInUTC(dateString) {
    return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm").setTimeZone(java.util.TimeZone.getTimeZone("UTC")).format(new java.text.SimpleDateFormat("yyyyMMddHHmm").setTimeZone(java.util.TimeZone.getTimeZone("CET")).parse(dateString));
}

祝您愉快 :)


我尝试了你的建议,但是出现了错误:TypeError: Cannot call method "format" of undefined。有什么想法吗? - kramer65
请导入java.text.SimpleDateFormat - Yogesh Rathi

0

你应该使用Java8提供的最新类java.time

步骤如下:

第一步:String解析为LocalDateTime

第二步:LocalDateTime转换为ZonedDateTime,然后我们可以在不同的时区之间进行转换。

希望这对你有所帮助:

在Mirth中,你可以这样写:

String str = "201207011000"; 
var date_in_utc =java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
                .format(java.time.ZonedDateTime.of(java.time.LocalDateTime
                .parse(str,java.time.format.DateTimeFormatter
                .ofPattern("yyyyMMddHHmm")),java.time.ZoneId.of("CET"))
                .withZoneSameInstant(java.time.ZoneOffset.UTC));

完整代码片段:

ZoneId cet = ZoneId.of("CET");
String str = "201207011000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
LocalDateTime localtDateAndTime = LocalDateTime.parse(str, formatter);
ZonedDateTime dateAndTimeInCET = ZonedDateTime.of(localtDateAndTime, cet );
System.out.println("Current date and time in a CET timezone : " + dateAndTimeInCET);
ZonedDateTime utcDate = dateAndTimeInCET.withZoneSameInstant(ZoneOffset.UTC);
System.out.println("Current date and time in UTC : " + utcDate);
System.out.println("Current date and time in UTC : " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").format(utcDate));

-2

嘿,Boosh。抱歉回复晚了。我尝试了你的建议,但是不幸的是第二行只得到了“RangeError: Date is invalid.”的错误。我记录了“d”,它是一个正确指向2018年1月1日上午10点的对象。不知道为什么不能使用“Date”。还有其他想法吗? - kramer65

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接