【问题标题】:Good algorithm to convert timestamp to a shorter alphanumeric representation将时间戳转换为更短的字母数字表示的好算法
【发布时间】:2011-03-23 13:06:55
【问题描述】:

什么是获取包含年、月、日、小时、分钟、秒的时间戳并将其转换为 7 位或更少(但一致)的字母数字表示的好算法。 字母数字表示不区分大小写字母。

【问题讨论】:

  • 大约有 6447 万个数字和字母组合(假设您同时使用大写和小写)。这还不到 2 年的秒数。你不会获得独特性;会有碰撞。
  • 必须是 6 个字符吗?如果没有,基于时间戳的 UUID 可能是一个很好的解决方案:en.wikipedia.org/wiki/Universally_unique_identifier
  • @wooble:我可能需要一些帮助,你的计算是什么?我得到了大约 568 亿个组合?
  • @Wooble.. 怎么样?会有 62^6 = 大约 528 亿个组合,对吧?应该持续超过 1000 年..
  • 我很困惑你是怎么得出6400万的?我似乎得到了20亿。我不怀疑你,因为我的数学能力很差,但请你解释一下。如果我的数学是正确的,那么也许 7 位数会起作用?

标签: algorithm


【解决方案1】:

让我们做一些数学运算

您可以使用 7 个字母数字。每个字母数字从 36 个可能的不同值中取一个值(26 个字母,10 个十进制数字) 所以我们有 36^7 个不同的值,即 78364164096。

现在我们计算在一年中表示给定时间戳所需的不同值的数量。 为了简化一点,我们将允许一些永远不会发生的值(例如:11 月 31 日)。

因此,我们有

month: 12  -> coded from 0 to 11
day: 31  -> coded from 0 to 30
hour: 24
minute: 60
second: 60 

这给出了使用 32140800 种不同的可能性

我们现在将 78364164096 / 32140800 相除,即 ~2438,因此我们将枚举从 0000 年 1 月 1 日 00:00 到 2437 年 12 月 31 日 23:59 的时间戳

那么编码就是

X = second + minute*60 + hour*60*60 + 
    day*60*60*24 + month*60*60*24*31 + 
    year*60*60*24*31*12

而解码是

second = X mod 60
minute = (X div 60) mod 60
hour = (X div 60*60) mod 24
day = (X div 60*60*24) mod 31
month = (X div 60*60*24*31) mod 12
year = X div 60*60*24*31*12

我们来看一个例子:

假设您想对 1998 年 12 月 20 日 05:33:12 的日期进行编码 所以你会有

second: 12
minute: 33
hour: 5
day: 19   -> note that we encode days in the range 0..31
month: 11  -> note that we conde months in the range 0..11
year: 1998

所以我们计算:

X = 12 + 33*60 + 5*60*60 + 
        19*60*60*24 + 11*60*60*24*31 + 
        1998*60*60*24*31*12

即X = 12 + 1980 + 18000 + 1641600 + 29462400 + 64217318400 = 64248442392

现在我们解码它

second = 64248442392 mod 60  = 12
minute = (64248442392 div 60) mod 60 = 33
hour = (64248442392 div 60*60) mod 24 = 5
day = (64248442392 div 60*60*24) mod 31 = 19
month = (64248442392 div 60*60*24*31) mod 12 = 11
year = 64248442392 div 60*60*24*31*12 = 1998

【讨论】:

  • 很抱歉,我的问题不够清楚,我将对其进行编辑。我不想区分小写和大写。由于这大大降低了可能性,我认为如有必要我会增加到 7 位数。
  • 我不得不承认我对你的回答有些困惑。也许您可以举一个时间戳及其编码的示例。
  • 然后我会做一个基本转换得到 7 位字母数字??
  • @Mike:是的,您必须进行基本转换(到基数 36)。对于每个数字,如果它小于 10,则添加 48(得到 '0'..'9'),否则从 10..36 开始添加 55(得到 'A'..'Z')跨度>
【解决方案2】:

考虑一个高于十进制的数字系统。例如,十六进制数字系统是以 16 为基数的。假设在我们的新数字系统中,我们有数字 0-9、小写字母 (a-z) 和大写字母 (A-Z)。这为我们提供了 62 个可能的数字,因此我们可以使用 base-62 数字系统。这是一些用于转换的 Javascript 代码 -

function createConverter() {
    var charRange = (start, end) => Array.from(Array(end-start), 
                                         (v, i) => String.fromCharCode(i + start))

    var digits = charRange(48, 48+10)             // 0 to 9
                   .concat(charRange(97, 97+26))  // a to b
                   .concat(charRange(65, 65+26))  // A to B

    var base = digits.length

    return function(decimal) {
            var result = ""
            while (decimal >= base) {
                result = digits[decimal % base] + result
                decimal = parseInt(decimal / base)
            }
            result = digits[decimal] + result
            return result
        }
}

var convert = createConverter()
convert(parseInt(Date.now() / 1000)) // returns a 6-digit alphanumeric string 

charRange 只是一个实用箭头函数,用于从 ASCII 码创建一系列字符

digits 代表我们数字系统中的所有有效数字。您可以在此列表中添加更多有效数字(如特殊字符)

base 是可用位数的个数(十进制)

以这种 base-62 数字系统编码的输出将保持 6 位数的长度超过 1,700 年。

编辑:Realized Date.now() 以毫秒而不是秒返回时间戳,所以我更新了我的答案以反映这一点

【讨论】:

  • 解码呢? :)
  • 为什么不使用 base 16,例如new Date().getTime().toString(baseNumber) 其中 baseNumber 可以是例如 16?
  • 当然 - toString 的基数值最高为 36,因此如果适合您,您将获得稍长的字符串。
【解决方案3】:

我在对a previous question 的回答中编写了用于将整数编码为短字符串的代码以及一些注意事项。

您仍然必须决定如何将日期时间映射到整数,但其他答案已经解决了这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多