You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言ulid包ULID未按毫秒排序?如何生成带毫秒时间戳的ULID

R语言ulid包毫秒级ULID生成问题解答

先说结论:ulid包完全支持毫秒级ULID,你遇到的排序和时间显示问题都是细节处理不到位导致的,不是包本身不支持。


1. 为啥100ms生成的ULID排序乱了?

默认调用generate()时,函数会自动抓取当前时间的毫秒数,但有两个容易踩的坑:

  • 系统时间精度限制:部分系统(比如旧版本Windows)的Sys.time()精度达不到毫秒级,连续调用时多个ULID的时间部分完全相同,此时随机部分是无序生成的,自然打破了字典序与生成顺序的一致性。
  • replicate执行特性:replicate的循环执行速度可能快于Sys.sleep(0.1)的实际延迟,导致多个ULID仍挤在同一毫秒内。

解决办法:手动传入毫秒级时间戳

自己生成精确的毫秒时间戳传给generate(),确保每个ULID的时间部分严格递增:

library(ulid)
library(stringi)

gen_ulid <- \(sleep) {
  res <- character(5)
  for (i in 1:5) {
    # 转换为从1970年开始的毫秒级时间戳
    ts_ms <- as.integer(Sys.time() * 1000)
    res[i] <- generate(timestamp = ts_ms)
    Sys.sleep(sleep)
  }
  res
}

# 再次测试100ms间隔生成
u <- gen_ulid(0.1)
stri_sort(u) == u
# 预期输出:[1] TRUE TRUE TRUE TRUE TRUE

2. 为啥转成POSIX时间戳看不到毫秒?

unmarshal(u)$ts返回的POSIXct类型本身支持亚秒精度,但存在两个显示层面的问题:

  • unmarshal将ULID的毫秒时间戳转换为POSIXct时,是除以1000得到秒数,R会保留小数部分,但默认打印不显示。
  • 你使用的format函数中,%OS3依赖系统时间精度设置,若系统精度不足,会显示为.000。

解决办法:直接解析ULID的时间部分

不用依赖unmarshal的POSIXct转换,直接从ULID字符串中提取时间部分解析:

# 自定义函数解析ULID的毫秒时间
parse_ulid_ms <- \(ulid_str) {
  # ULID前10位是Base32编码的毫秒时间戳
  ts_base32 <- substr(ulid_str, 1, 10)
  # 转换为十进制毫秒数
  ts_ms <- ulid:::base32_decode(ts_base32)
  # 转换为带毫秒的POSIXct
  as.POSIXct(ts_ms / 1000, origin = "1970-01-01", tz = Sys.timezone())
}

# 测试解析
u <- gen_ulid(0.1)
ts_with_ms <- parse_ulid_ms(u)
format(ts_with_ms, "%Y-%m-%d %H:%M:%OS3")
# 预期输出会显示不同的毫秒值,例如:
# [1] "2024-05-30 14:30:05.156" "2024-05-30 14:30:05.257" "2024-05-30 14:30:05.358"
# [4] "2024-05-30 14:30:05.459" "2024-05-30 14:30:05.560"

另外,也可以直接查看unmarshal返回时间的小数部分(即毫秒):

df <- unmarshal(u)
# 查看秒数的小数部分(对应毫秒)
df$ts - as.integer(df$ts)
# 输出类似:Time differences in secs
# [1] 0.156 0.257 0.358 0.459 0.560

额外提醒

  • 先更新ulid包:旧版本可能存在时间戳处理的bug,执行update.packages("ulid")更新到最新版。
  • 若在同一毫秒内生成多个ULID,ulid包会自动保证随机部分单调递增,因此即使时间相同,字典序仍与生成顺序一致。

内容的提问来源于stack exchange,提问作者Mark Heckmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 02:19:57