如何使用Java从UUID中提取日期?

20
如何将 UUID 转换为日期格式 2011-04-22
例如,我有这样的 UUID:
118ffe80-466b-11e1-b5a5-5732cf729524.

如何将此转换为日期格式?我尝试了。
 String uuid="118ffe80-466b-11e1-b5a5-5732cf729524"; 
    UUID uid = UUID.fromString(uuid);
    long ls=convertTime(uid.timeStamp()); // it returns long value

    public String convertTime(long time){
            System.out.println("====="+time);
            Date date = new Date(time);
            Format format = new SimpleDateFormat("yyyy/MM/dd");
            return format.format(date).toString();
        }

我得到的输出结果是:4294744/11/02

同样的情况在Perl中运行良好。

$uuid='ef802820-46b3-11e2-bf3a-47ef6b3e28e2';
$uuid =~ s/-//g;

my $timelow = hex substr( $uuid, 2 * 0,     2 * 4 );
my $timemid = hex substr( $uuid, 2 * 4,     2 * 2 );
my $version = hex substr( $uuid, 2 * 6,     1 );
my $timehi  = hex substr( $uuid, 2 * 6 + 1, 2 * 2 - 1 );

my $time = ( $timehi * ( 2**16 ) + $timemid ) * ( 2**32 ) + $timelow;
my $epoc = int( $time / 10000000 ) - 12219292800;
my $nano = $time - int( $time / 10000000 ) * 10000000;

#$time_date = scalar localtime $epoc;
#print strftime( '%d-%m-%Y %H:%M:%S', localtime($epoc) );
#print "\n Time: ", scalar localtime $epoc, " +", $nano / 10000, "ms\n";

请检查此网址:https://dev59.com/B2_Xa4cB1Zd3GeqPwQZ6 - BALASCJP
你知道那个源UUID是v1 UUID吗? - Joe
timeStamp() 返回自1582年10月15日午夜以来以100纳秒为单位测量的时间戳;Date(long date) 期望接受自1970年1月1日00:00:00 GMT以来的毫秒数。因此,您需要将一种格式转换为另一种格式。 - tmuguet
2
@JonSkeet 根据 UUID 算法的版本不同,它可能包含一个时间戳。 - assylias
2
@assylias: 它很可能包含一个时间戳,但这并不意味着要转换整个值。如果问题是“如何提取UUID的时间戳部分”,那将是另一回事。 - Jon Skeet
1个回答

23

UUID的javadoc关于时间戳字段有以下说明:

60位时间戳值是由此UUID的time_low、time_mid和time_hi字段构成的。结果得到的时间戳是自1582年10月15日UTC协调世界时午夜以来的100纳秒单位的时间

(强调是我加的)

Java时间戳是自1970-01-01以来的毫秒数。为了从UUID中获取有意义的日期,您需要做两件事: 将100纳秒转换为1毫秒精度(除以10000),并从1582-10-15重新基准到1970-01-01,这可以通过添加一个常量值来完成。

WolframAlpha告诉我们,1582-10-15对应于UNIX时间戳-12219292800,因此要得到正确的日期,必须将12219292800加上你在除以10000后得到的毫秒数。

另外需要注意的是:

时间戳值仅在基于时间的UUID(版本类型1)中有意义。如果此UUID不是基于时间的UUID,则此方法会抛出UnsupportedOperationException异常。

...因此,请确保你的代码只遇到类型1 UUID或能够处理它们没有时间戳的情况。


2
你是指 new Date(uid.timeStamp() / 10000L + 12219292800L) 吗?我可以给你一个例子,但我相信你能自己解决 :)。 - Barend
9
根据我的测试,答案是错误的。请参考https://support.datastax.com/entries/22391451-Converting-TimeUUID-Strings-to-Dates中提供的解决方案,这个解决方案对我很有效。 - Iker Jimenez
1
@peterl 这是我一直在使用的代码,本应该放在回答中,但问题已关闭,因此对于格式不佳的部分请谅解:private static final long NUM_100NS_INTERVALS_SINCE_UUID_EPOCH = 0x01b21dd213814000L; UUID uuid = UUID.fromString(aUuid); long epoch = (uuid.timestamp() - NUM_100NS_INTERVALS_SINCE_UUID_EPOCH) / 10000; - Iker Jimenez
2
“-12219292800” 对应于标准 Unix 时间戳的 “1582-10-15 00:00:00”,时间单位是“秒”,而不是毫秒,这可能导致答案不正确。您应该将此常量乘以1000,以获得毫秒值,然后将其添加到UUID时间戳中,该时间戳已被除以10000以将其转换为毫秒。这样它们都是以毫秒为单位的。您需要加上两个时间戳,因为公历时间戳与时代时间戳之间存在负关系。 - Anthony
3
这个代码作用是通过给定的UUID时间戳,计算出对应的日期时间。具体做法是将时间戳除以10000并减去12219292800000L,然后将得到的结果作为参数创建一个新的Date对象。这个方法是根据https://www.famkruithof.net/guid-uuid-timebased.html中给出的数值进行实现的。 - Sergey Ponomarev
显示剩余4条评论

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