一起学Rust–环境搭建与安装

Rust是一种安全、并发、实用的编程语言,有着惊人的运行速度,能够防止段错误,并保证线程安全,使每个人都能够构建 可靠,高效的软件。

这是中文官网给出的Rust语言介绍。

经过尝试,可以说Rust在编译器中花了很多的时间,做出了很多的限制,比起其他的比如C/C++/Java等语言,在编译阶段会涉及更多的检查,以防止开发者在编写代码中出现不必要的代码层面的Bug。

闲言碎语不要讲,直接进入主题。

Linux下安装

curl https://sh.rustup.rs -sSf | sh

或者可以直接从浏览器访问https://sh.rustup.rs,会自动下载安装脚本。脚本运行时会识别当前系统,cpu类型等信息,到拼接出来到https://static.rust-lang.org/rustup/dist/<cpu-type – system>/rustup-init地址去下载相对应到安装程序。

如果你明确知道自己到机器cpu架构和系统,也可以直接到这里下载https://forge.rust-lang.org/other-installation-methods.html

Windows下安装

window下可以从https://forge.rust-lang.org/other-installation-methods.html链接内到“Other ways to install”小节内下载rustup-init.exe。

MacOS下安装

Mac下安装相对选择较多,可以使用上述两种方式均可,也可以通过brew安装。

brew install rust

所有相关程序默认安装至“/usr/local/Cellar/rust/<version>/bin” ,这是与官网提供到安装脚本不同的地方,官方脚本会将程序安装至~/.cargo/bin中。

配置环境

Linux环境:如果自动配置异常,则需手动配置。

export PATH="$HOME/.cargo/bin:$PATH" >> ~/.bash_profile

Windows环境:通常会自动配置,如果没有则需要手动配置

右键“我的电脑/计算机”–>“属性”,选择左侧“高级系统设置”,会弹出“系统属性”框,点击底部“环境变量”,点击上面的框中“Path”,选择编辑:Win10可以在弹出的编辑框中选择添加,将安装程序(bin目录)的完整路径配置进去,Win7及之前的则需要直接输入路径,与已有的文字以英文分号隔开。

Mac环境下无需配置。

Cargo命令

Cargo算不上比rustc等命令快速,但是它是可以管理项目和依赖包,尤其是当构建较大的项目时会凸显它的优势,所以我们直接学习cargo的使用。

新建一个项目:

cargo new rust-demo

编译项目:

cargo build

编译前检查

cargo check

编译并运行

cargo run

Cargo build 除了编译项目,还有一个作用就是安装依赖包,依赖包会写在Cargo.toml中

在[dependencies]配置块中,每行一个:

[dependencies]
xxxx=1.0.0

通常cargo build编译的是debug版本。构建发布版本:

cargo build --release

MySQL中Datetime与Timestamp

“温故而知新”

真理永远都不过时,今天由于工作的事情涉及到了这里,印象中只记得DateTime类型占用8字节,TimeStamp类型占用4字节,心想这么久没有更新的知识万一过时了咋办,于是翻开了MySQL的官网,决定查一查这两个字段的区别。

打开官网,扑面而来的英文字母刺的眼睛生疼,揉了揉眼睛,定心下来查一查。官网这么大,怎么搜,想起来目前在用的是MySQL 5.7版本,那就先查查5.7版本的文档吧。

废话不多说,先把结果拿出来。

  1. v5.6.4版本之前DateTime占用8字节,TimeStamp占用4字节。
  2. v5.6.4版本开始DateTime非小数时间部分仅占用5字节,如果有秒的小数部分会占用0-3个字节,v5.6.4版本开始TimeStamp非小数部分占用4个字节,小数部分占用0-3个字节。
  3. v5.6.4版本之前DateTime是分为两部分,分别是4字节的整数存储的;TimeStamp是以时间戳整数的形式存储的4字节。
  4. v5.6.4版本开始,DateTime的数据结构变化较大,后面详细介绍,TimeStamp基本相同只是又小端序改为大端序。

(在v5.5.x中是没有小数部分的)

好~下面详细介绍一下

按官网给出的表格大概是这样的

Data TypesBefore 5.6.4 As of 5.6.4
DATETIME8 bytes5 bytes + fractional seconds storage
TIMESTAMP4 bytes4 bytes + fractional seconds storage

举个例子比如同样的 DATETIME类型的时间 “2019-07-29 17:30:33” 在v5.6.4之前就是占用8字节,从v5.6.4开始,仅占用 5字节。

下面的表格是小数部分不同精度所占用的字节数

Fractional Seconds PrecisionStorage Required
00 bytes
1, 21 byte
3, 42 bytes
5, 63 bytes

举例:DATETIME(4),会保存精度为4的时间,会占用5 + 2 = 7bytes,DATETIME(3)与DATETIME(4),DATETIME(0)与DATETIME一样,只占用5字节。

由于好奇,我点开了让我眼前一亮的一个章节。

“Important Algorithms and Structures” — “重要的算法和结构”

v5.6.4版本之前:

TIMESTAMP内部是以一个正整数来存储的,所以占用4字节,最小是0,转化为时间就是1970-01-01 00:00:00(UTC),而最大是2^31 – 1 转化为 UTC时间就是2038-01-19 03:14:07,如果是中国时区就是UTC+8 2038-01-19 11:14:07(TIMESTAMP会以UTC时区存储)

DATETIME内部占用8字节,以两个四字节整数组合而成的数据,假设有一个YYYY-MM-DD hh:mm:ss格式的日期,日期部分占用4字节等于YYYY*10000 + MM * 100 + DD,时间部分等于hh*10000 + mm*100 + ss。

v5.6.4开始DATETIME类型发生了关键性变化,下面贴上官网原文:

 1 bit  sign           (1= non-negative, 0= negative)
17 bits year*13+month  (year 0-9999, month 0-12)
 5 bits day            (0-31)
 5 bits hour           (0-23)
 6 bits minute         (0-59)
 6 bits second         (0-59)
---------------------------
40 bits = 5 bytes

第一位是符号位,后面的day、hour、minute、second都可以理解,2^5=32 可以表示31一下的全部数字,2^6=64 可以表示59以下的数字。

最关键的就是年和月的存储方式,有的小伙伴说直接分别存储年和月不行吗?

行是行,但是不是最优,这里我们计算一下,要想最大表示9999需要多少bits,答案是14,2^13=8192,2^14=16384,所以最大9999的年需要14bits,而月份最大是12,需要4bits,2^4=16 > 12。

这样一来,年和月就要占用18bits,多占用了1bits,就是这么较真儿,1bits也不多给。

那么问题来了,这1bits是怎么省出来的?为什么官方给出的算法是year*13+month

这个可以说非常巧妙了,因为月份的范围很小,在1bits的指数增长范围内渺小的很,可以利用这个将月份和年放到一起存储,可是有个问题,放一起好放,怎么准确的拆分还原呢?

关键时刻数学起作用,月份范围是1-12,这个数据总能在一定的范围内移动,这不就是取余所具有的性质的嘛!余数总是小于除数,月份最大12,所以选择13作为除数,这就是为什么是用13乘以年加上月份,得到存储值。

最大9999 * 13 + 12 = 129999,恰好小于2^17 = 131072,其实这样完全可以最大表示到10004年,但9999以完完全全足够使用了。

这次经过查阅官网,收获了很多,而且还有很多其他内容,篇幅有限,有了新的理解再进行分享。

最后一点个人想法,5.6.4开始的版本再定义时间建议使用DATETIME,业务无要求的情况仅使用非小数部分就可以了,仅比TIMESTAMP多一个字节,但是范围要大很多,而且DATETIME相比之前存储、计算速度有了一定的提升; TIMESTAMP使用到2038年1月19号就到终点站了……

希望大家的项目到那时还存在,我的也是~~

贴出官网文档:

底层算法和结构: https://dev.mysql.com/doc/internals/en/date-and-time-data-type-representation.html

日期时间类型概览:https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html

不仅仅是DATETIME和TIMESTAMP,还有DATE,TIME,YEAR的介绍。

PS:右上角可以选择文档版本,查看不同版本的MySQL的区别。

再见~

JSON格式化

我个人主要是做一些后端的工作,比如php、python、c之类的,c比较少,最主要的是php,不过我非常喜欢js,所以经常会愿意去写一些小玩意自娱自乐。

今天在测试接口的时候,使用原生js的XMLHttpRequest去请求,直接使用document….innerHTML输出到页面,因为没有浏览器的json格式化没有生效,所以接口响应的json数据就看起来很不舒服。

于是乎,我就想起了为啥我自己不能实现一个,应该不是很难吧。

我仔细思考了一下,这玩意不就是遇到大括号、中括号和中括号就换行吗,每行还有个缩进,人家再高级一点的还有颜色,折叠功能、缩进对齐线之类的,于是我觉得一步一步来,先把格式化和颜色实现出来,后面的折叠、动画和缩进对齐线再慢慢做。

电影有句话说的好啊:“步子迈大了,咔,容易扯着蛋”。

扯了这老些没用的,下面开始我的正经思路:

合法的JSON字符串是一个单行字符串,边界符号是“{} []”,键值对之间是以英文逗号“,”作为分隔,键和值之间是用英文冒号“:”进行分隔。JSON内的字符串必须以双引号包括在外侧,数字类型或布尔类型可以不使用双引号包括。逗号分隔符的后面必须至少存在一个键值对(即末尾的键值对的后面不能有逗号分隔符了,这里的逗号指的是键值对分隔符,而不是指值内的逗号字符串)。

看看别人优秀的是什么样子的。

从某平台的json格式化服务截取

可以发现在“{, [”的后面都会有一个换行,每个键值对的后面都有一个换行,在符号“], 和 }, ”的后面都会有一个换行。

而且格式化后的JSON是有“结构区块”的,从缩进来区分不同的结构块,这一点有点像python,不过这有点牵强,格式化这样做的目的是为了能够很清晰的查看JSON的结构,与python的目的是有本质的区别的。

从截图来看,只要遇到一个“{ 或 [”,就要出现缩进,而且可以看出,缩进是随着遇到的个数增加的,这是成正比啊。而且只要遇到“]或}”,缩进就要少一个。

说到这里是不是就有感觉了,缩进就是在匹配括号啊,这匹配括号在逆波兰式里的操作啊,不就是基础的数据结构“栈”吗。

那我对整个字符串进行遍历判断是不就能做到了,那有了思路就可以动手了,能动手我就不在这里扯🥚了。

<!-- 这里在页面放一个pre标签,让输入的结构按照我们需要的形式展现 -->
<pre id="json"></pre>

假设我有一个jsonStr,我想要格式化它。

var jsonStr = '{"state":{"code":0,"success":true,"ok":1},"body":[{"count":2394,"dbName":"star_all"},{"count":133,"dbName":"star"},{"count":7,"dbName":"zy"},{"count":1,"dbName":"gordon_test"}]}';

实现格式化方法,创建一个新的临时空字符串变量,用于保存格式化后的JSON串,创建栈用于计算缩进量。

function format(str){
    var stack = []; //栈-用于括号匹配
    var tmpStr = '';    //新格式化JSON字符串
    var len = str.length;   //原始JSON长度

    //遍历每一个字符
    for (let i = 0; i < len; i++) {

        //当遇到结构块起始结构
        if (str[i] == '{' || str[i] === '[') {

            //起始结构后面直接换行  
            tmpStr += str[i] + "\n";

            //入栈
            stack.push(str[i]);
            
            //这里的意思是结构块起始的下一行开始就会有一个缩进,缩进量与遇到的结构块起始符个数成正比1:1
            tmpStr += "\t".repeat(stack.length);
        } 
        //当遇到结构块结束符
        else if (str[i] == ']' || str[i] === '}') {

            //因为本身JSON格式是固定的,所以括号一定是成对的,这里先不考虑错误的json数据
            //遇到结束符就退栈,
            stack.pop();

            //结束符本身输出到下一行,并减少一个缩进
            tmpStr += "\n"+"\t".repeat(stack.length) + str[i];
        } 
        //当遇到逗号的时候
        else if (str[i] == ',') {
            //逗号后方直接换行,以及下一行的缩进处理
            tmpStr += str[i] + "\n" + "\t".repeat(stack.length);
        } 
        else {
            //其他字符直接复制
            tmpStr += str[i];
        }
    }
    return tmpStr;
}

返回的数据放到<pre>标签内

document.querySelector('#json').innerHTML = format(jsonStr);

输出的效果如下图

制表符\t稍微有点远,当然使用4个 也可以,别纠结~

这黑白色的不美观,那就给上个色呗,看看人家的,括号一个颜色,键值对一个颜色,值一个颜色,我不能抄它的,我觉得字符串,数字、布尔都分别用一种颜色就行,这个实现就都能实现了。

那既然需要分开使用不同的颜色,那么必然就涉及CSS了,每个结构就得有HTML结构了,我直接用正则是不是就解决了。

先写个CSS样式把

.bold{
    font-weight: 900;
}
.string-color {
    color: darkred;
}
.token {
    color: darkgreen;
}
.number {
    color: green;
}
.bool {
    color: orange;
}
//使用捕获,匹配全部的边界符号,class使用token
tmpStr = tmpStr.replace(/([\{\[\]\}])/g, '<span class="token bold">$1</span>');
//使用零宽断言和捕获,匹配全部的两侧是双引号的字符串,class使用string
tmpStr = tmpStr.replace(/(?<=\")(\w+)(?=\")/g, '<span class="string bold">$1</span>');

零宽断言就是匹配一个位置,分负向零宽断言和正向零宽断言,不知道的可以搜索一下。

//使用零宽断言,匹配全部的前面位置是冒号,后面是逗号或换行的数字类型值
tmpStr = tmpStr.replace(/(?<=\:)(\d+)(?=[\,\n])/g, '<span class="number bold">$1</span>');
//同理匹配布尔,
tmpStr = tmpStr.replace(/(?<=\:)(true|false)(?=[\,\n])/g, '<span class="bool bold">$1</span>');
效果还行

到这里就初步完成了一个还算能入眼的基础JSON格式化小方法。后续再加个闪电爆炸的特效,下次再分享~

正则匹配日期时间

由于比较好奇如何用正则完美匹配日期时间,于是发现了一位不知名的大神贡献的一套正则表达式

看起来相当复杂,分析了好长时间,下面贴出来给大家看一下

((\d{2}(([02468][048])|([13579][26]))[-/\s]?((((0?[13578])|(1[02]))[-/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[-/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[-/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[-/\s]?((((0?[13578])|(1[02]))[-/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[-/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[-/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))

但是我经过测试发现,这个表达式是存在一些小问题的,比如: 1980-2-29只能匹配到1980-2-2;而2100-2-29(2100年非闰年)是会发生匹配的,这样就会出现闰年和日期匹配不正确的情况。

phpstorm 插件 Regex Tester

于是,我在这个基础上做了一些修改,先把结果贴出来然后在做一下说明

(((((([2468][048])|([13579][26]))00)|(\d{2}((([2468][048])|([02468][48]))|([13579][26]))))[-/\s]?((((1[02])|(0?[13578]))[-/\s]?(([1-2][0-9])|(3[01])|(0?[1-9])))|(((11)|(0?[469])) [-/\s]?(([1-2][0-9])|(30)|(0?[1-9])))|(0?2[-/\s]?(([1-2][0-9])|(0?[1-9])))))|((((([2468][1235679])|([13579][01345789]))00)|(\d{2}(([02468][1235679])|([13579][01345789]))))[-/\s]?((((1[02])|(0?[13578]))[-/\s]?(([1-2][0-9])|(3[01])|(0?[1-9])))|(((0?[469])|(11)) [-/\s]?(([1-2][0-9])|(30)|(0?[1-9])))|(0?2[-/\s]?((1[0-9])|(2[0-8])|(0?[1-9]))))))

以下是对这个正则的解析:

日期和时间的匹配均是数字,但是年月日时分秒之间的有效范围是有一些区别的,所以导致整个正则表达式非常复杂。

首先分析年份的匹配,年份在有效范围内是最多4位的整数,而且会分为平年和闰年,下面贴出闰年年份的匹配部分

(((([2468][048])|([13579][26]))00)|(\d{2}((([2468][048])|([02468][48]))|([13579][26]))))

有同学说了,你的年份都放在一起进行条件匹配不行吗?

真的不行,因为闰年内的二月是29天,平年是不允许匹配到29这一天的,所以要把日期整体作为条件分支。

这一串匹配闰年的正则要怎么看呢?如何得出的呢?下面分析一下

闰年定义:满足能被400整除,或被4整除且不能被100整除,举个例子:2004满足被4整除且不能被100整除,所以是闰年;2000满足能被400整除,所以是闰年;2100年两个条件均不满足,平年。

这个定义写成编程语言:

(year % 400 === 0 || ( year % 4 === 0 && year % 100 !== 0 ))

判断条件已知了,但是正则表达式内如何匹配4的倍数,400的倍数,非100的倍数?

经过查阅: 4的倍数有以下特征:

(1)十位数为偶数时且个位是4的倍数的(含0);十位[2,4,6,8], 个位[0,4,8]

(2)十位数为奇数且个位数为偶数且个位数字不是4的倍数;十位[1,3,5,7,9],个位[2,6]

(3)十位和个位可被4整除则此数字即可被4整除;十位[0,4,8],个位[0,4,8]

100的整数倍可想而知,大于等于100,且个位与十位均为0。同理400倍就是结合二者,大于等于400,个位十位均为0,将数字除以100后满足4的倍数的特征。

这样,闰年应该如何书写和判断分支就明朗了,如下列出

I. 匹配可被400整除的年份

((([2468][048])|([13579][26]))00)

II. 匹配可被4整除但不能被100整除的年份

(\d{2}((([2468][048])|([02468][48]))|([13579][26])))

然后就是匹配月份,月份的匹配相对简单很多,需注意的 即使2月分的29号 和区别大小月份,1 3 5 7 8 10 12 这些是大月,这没什么好讲的

((((1[02])|(0?[13578]))[-/\s]?(([1-2][0-9])|(3[01])|(0?[1-9])))|(((11)|(0?[469]))[-/\s]?(([1-2][0-9])|(30)|(0?[1-9])))|(0?2[-/\s]?(([1-2][0-9])|(0?[1-9]))))

月份这里解决的一个问题就是上面说的月份匹配错误(2-29只能匹配2-2)

改动前:(0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))
改动后:([1-2][0-9])|(3[01])|(0?[1-9])))|(((11)|(0?[469]))

原因是:原作者将最初补零的验证置前,且0为匹配1次或0次,则匹配到[1-9]后不再进行 ‘或’ 后的匹配

后面的就是正常的年份匹配了

(((([2468][1235679])|([13579][01345789]))00)|(\d{2}(([02468][1235679])|([13579][01345789]))))

平年的匹配很简单,不满足闰年条件的年份就是平年。

经过测试,年月日可以正常匹配了,不过实际工作中这种过长的正则还是尽量不要用或者少用,虽然计算机执行起来对于人来说是几乎无感的,但是效率相对来说要低一些,日期判断是否有效有很多函数工具可以满足。

不过这个正则对于分析正则以及学习它的条件匹配还是有好处的。

Thanks

数据结构-php实现循环队列

该图片由www_slon_picsPixabay上发布

队列(Queue): 满足先进先出(FIFO)的规则;

下面使用php实现一个简单的循环队列模型;

初始状态的队列,队列长度为0,队头和队尾的指针相同均位于队列的开始;

入队操作:队尾指针向后移动,长度加一;

出队操作:队头指针向后移动,长度减一;

循环队列特点:队列大小固定,队列所开辟的内存空间可循环使用,指针的偏移量是靠与队列长度取余运算得出的;

<?php


/**
 * Class Queue
 */
class Queue
{
    /**
     * @var int 队头指针
     */
    private $_front;

    /**
     * @var int 队尾指针
     */
    private $_rear;

    /**
     * @var array 队列数组
     */
    private $_queue;

    /**
     * @var int 队列实际长度
     */
    private $_queueLength;

    /**
     * @var int 队列容量;
     */
    private $_queueSize;

    /**
     * Queue constructor.初始化队列
     * @param int $capacity 容量(循环队列的最大长度)
     */
    public function __construct($size)
    {
        $this->_queue = [];
        $this->_queueSize = $size;
        $this->_front = 0;
        $this->_rear = 0;
        $this->_queueLength = 0;
    }

    /**
     * 销毁队列;
     */
    public function __destruct()
    {
        unset($this->_queue);
    }

    /**
     * @method 入队
     * @param mixed $elem 入队的元素
     * @return bool
     */
    public function enQueue($elem)
    {
        if (!$this->isFull()) {
            $this->_queue[$this->_rear] = $elem;
            $this->_rear++;
            $this->_rear = $this->_rear % $this->_queueCapacity;
            $this->_queueLength++;
            return true;
        }
        return false;
    }

    /**
     * @method 出队
     * @return mixed|null
     */
    public function deQueue()
    {
        if (!$this->isEmpty()) {
            $elem = $this->_queue[$this->_front];
            //unset($this->_queue[$this->_front]);
            $this->_front++;
            $this->_front %= $this->_queueCapacity;
            $this->_queueLength--;
            return $elem;
        }
        return null;
    }

    /**
     * @method 判断队列是否为空;
     * @return bool
     */
    public function isEmpty()
    {
        return $this->_queueLength === 0;
    }

    /**
     * @method 判断队列是否饱和;
     * @return bool
     */
    public function isFull()
    {
        return $this->_queueLength === $this->_queueCapacity;
    }

    /**
     * @method 遍历队列并输出(测试队列)
     */
    public function outputQueue()
    {
        for ($i = $this->_front; $i < $this->_queueLength + $this->_front; $i++) {
            echo $this->_queue[$i % $this->_queueCapacity].PHP_EOL;
        }
    }

    /**
     * @method 清空队列
     */
    public function clearQueue()
    {
        $this->_queue = [];
        $this->_front = 0;
        $this->_rear = 0;
        $this->_queueLength = 0;
    }
}

然后进行一下测试

$a = new Queue(3);
echo 'enQueue1 $a->enQueue(1)'.PHP_EOL;
$a->enQueue(1);
echo 'enQueue2 $a->enQueue(2)'.PHP_EOL;
$a->enQueue(2);
echo 'enQueue3 $a->enQueue(3)'.PHP_EOL;
$a->enQueue(3);
echo 'enQueue4 $a->enQueue(4)'.PHP_EOL;
$a->enQueue(4);     //讲道理是失败的;
$a->outputQueue();      //输出 1 2 3
echo PHP_EOL;
echo PHP_EOL;
echo $a->deQueue();     //输出 1  队列 2 3
echo PHP_EOL;
echo PHP_EOL;
echo $a->deQueue();     //输出 2  队列 3
$a->enQueue(5);         //队列 3 5
echo PHP_EOL;
echo PHP_EOL;
$a->outputQueue();      //输出 3 5
$a->clearQueue();       //队列空;

JS 获取时间戳

JS如何获取时间戳

一、 获取当前时间戳

//获取时间戳 单位:秒;

//1. 获取当前时间戳
function getUnixTime(){
    var date = new Date();
    //使用getTime方法;
    var unix_time = date.getTime();

    //使用parse方法;
    var unix_time = Date.parse(date);

    //使用valueOf()方法;
    var unix_time = date.valueOf();

    //js获取的时间戳为毫秒级;转换为秒;
    return Math.round(unix_time / 1000);
}

二、获取指定日期的时间戳

//2. 获取指定时间的时间戳
//这种的获取时间戳对时间格式有限制; 如2016-04-28 09:04:30或2016/04/28 09:04:30或04-28-2016 09:04:30或者04/28/2016 09:04:30
function getUTime(time){
    var d = Date.parse(time);
    return d;
}

三、简单的正则匹配日期字符串中的日期时间

//3. 匹配时间字符串中的日期、时间;
function getUTime1(time){
    var exp = /\d+/g;
    var date = time.match(exp);
    console.log(date);      
}
getUTime1('01/10/1992 12:12:12');   // 输出["01", "10", "1992", "12", "12", "12"]

四、获取毫秒时间戳

//4. 当分别有年、月、日、时、分、秒时获取时间戳;
// 这里所有参数都是非必填;
// 这里month需注意:一月是从0开始;
var d = new Date(year, month, day, hour, minute, second);
console.log(Date.parse(d));     // 获取的时间戳为毫秒;