简体   繁体   English

从ISO 8601日期字符串转换为BigQuery时间戳时出错

[英]Error when converting to BigQuery timestamp from ISO 8601 date string

I have an ISO 8601 date string in the following format: 我有以下格式的ISO 8601日期字符串:

String myIsoDateString = "2019-02-27T23:00:00.000Z"

I need to use the date string as part of a query I'm running in BigQuery. 我需要在BigQuery中运行的查询中使用日期字符串。 I'm trying to use the com.google.cloud.bigquery.QueryParameterValue class to convert it to a QueryParameterValue , with a type of timestamp , like this: 我正在尝试使用com.google.cloud.bigquery.QueryParameterValue类将其转换为带有timestamp类型的QueryParameterValue ,如下所示:

QueryParameterValue.timestamp(myIsoDateString)

This gives me an error: 这给我一个错误:

java.lang.IllegalArgumentException: Invalid format: "2019-02-27T23:00:00.000Z" is malformed at "T23:00:00.000Z"

The inline help in Eclipse for the timestamp method states that it: Eclipse中的timestamp方法的内联帮助指出:

Creates a QueryParameterValue object with a type of TIMESTAMP. Must be in the format"yyyy-MM-dd HH:mm:ss.SSSSSSZZ", e.g. "2014-08-19 12:41:35.220000+00:00".

How do I convert myIsoDateString to the required format? 如何将myIsoDateString转换为所需的格式? Is there a better method I can use that will handle converting from an ISO 8601 string to a timestamp in BigQuery? 我是否可以使用更好的方法来处理从ISO 8601字符串到BigQuery中的时间戳的转换?

I would expect the answer the answer by Felipe Hoffa to work and give you what you want: replace the T with a space. 我希望Felipe Hoffa的答案能起作用,并给您您想要的东西:用空格替换T Here are a couple of other suggestions. 这里还有其他一些建议。

Be explicit: While the documentation gives a quite clear example of an expected string, it's not clear from the error message nor from the documentation (link below, but you've got it in Eclipse already) whether QueryParameterValue.timestamp accepts the Z as an offset. 明确一点:虽然文档中给出了预期字符串的非常清晰的示例,但是从错误消息或文档中也不清楚(下面的链接,但是您已经在Eclipse中找到了它) QueryParameterValue.timestamp是否接受Z作为偏移量。 If we want to be sure and also be more explicit about supplying the format asked for (always nice for those managing your code after you): 如果我们想确定并且更明确地提供所要求的格式(对于那些在您之后管理代码的人总是很好的):

    DateTimeFormatter timestampFormatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSxxx");
    String myIsoDateString = "2019-02-27T23:00:00.000Z";
    OffsetDateTime dateTime = OffsetDateTime.parse(myIsoDateString);
    QueryParameterValue.timestamp(dateTime.format(timestampFormatter));

This passes the string 2019-02-27 23:00:00.000000+00:00 to timestamp . 这会将字符串2019-02-27 23:00:00.000000+00:00传递给timestamp

Pass a long: timestamp comes in an overloaded version taking a Long argument. 通过长: timestamp进来的重载版本采取了Long的说法。 Again it's not documented what the long value should be. 同样,没有记录长值应该是什么。 Edit: Your own answer revealed that timestamp(Long) requires microseconds since the epoch. 编辑:您自己的答案显示, timestamp(Long)自纪元以来需要微秒。 The fully correct way to convert without any risk of unnecessary loss of precision is: 没有任何不必要的精度损失风险的完全正确的转换方法是:

    String myIsoDateString = "2019-02-27T23:00:00.000Z";
    Instant dateTime = Instant.parse(myIsoDateString);
    long microsecondsSinceEpoch = TimeUnit.SECONDS.toMicros(dateTime.getEpochSecond())
            + TimeUnit.NANOSECONDS.toMicros(dateTime.getNano());
    QueryParameterValue.timestamp(microsecondsSinceEpoch);

A value of 1 551 308 400 000 000 is passed to timestamp . 将1 551 308 400 000 000的值传递给timestamp

Disclaimer: I'm not a BigQuery user. 免责声明:我不是BigQuery用户。

Links 链接

The error says this is not the right format: 该错误表明这不是正确的格式:

 "2019-02-27T23:00:00.000Z"

But this one would be: 但这将是:

 "yyyy-MM-dd HH:mm:ss.SSSSSSZZ"

Try replacing the T between date and time with a 尝试将日期和时间之间的T替换为 .

ISO 8601 versus SQL ISO 8601与SQL

The ISO 8601 standard uses a T in the middle to separate the year-month-day portion from the hour-minute-second portion. ISO 8601标准在中间使用T来将年月日部分与时分秒部分分开。

The SQL style uses a SPACE in the middle rather than a T . SQL样式在中间使用SPACE而不是T

Replace. 更换。

String input = "2019-02-27T23:00:00.000Z".replace( "T" , " " ) ;
QueryParameterValue.timestamp( input ) ;

Ditto for going the other direction. 同上另一个方向。 The java.time classes use the ISO 8601 formats by default when parsing/generating text. 解析/生成文本时, java.time类默认使用ISO 8601格式。

String input = "2019-02-27 23:00:00.000Z".replace( " " , "T" ) ;
Instant instant = Instant.parse( input ) ;
ZonedDateTime zdt = instant.atZone( ZoneId.of( "Pacific/Auckland" ) ) ;

This works: 这有效:

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

Convert myIsoDateString to microseconds and store it as a long : myIsoDateString转换为微秒,并将其存储为long

long myDateInMicroseconds = DateTime.parse(myIsoDateString).toDateTime(DateTimeZone.UTC).getMillis() * 1000;

Then pass it as the argument to QueryParameterValue.timestamp: 然后将其作为参数传递给QueryParameterValue.timestamp:

QueryParameterValue.timestamp(myDateInMicroseconds)

To anyone who is just trying to parse ISO 8601 in BigQuery (this post is the first Google result), try this: 对于只想在BigQuery中解析ISO 8601(本文是Google的第一个结果)的人,请尝试以下操作:

SELECT
PARSE_TIMESTAMP('%Y-%m-%dT%H:%M:%E*SZ',  '2018-10-12T13:22:27.120Z')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM