爱技术 & 爱分享
爱蛋蛋 & 爱生活

时间

Shadow阅读(3088)

这篇文章算是个科普,讲一下时间相关的知识…

首先我们来介绍一下时间相关的术语,GMT,UTC,Locale Time,Unix时间戳,原子时

GMT

GMTGreenwich Mean Time 的缩写(中文:格林尼治标准时间),是指位于英国伦敦郊区的皇家格林尼治天文台当地的标准时间,因为本初子午线被定义为通过那里的经线。

自1924年2月5日开始,格林尼治天文台负责每隔一小时向全世界发放调时信息。

理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间。

但由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能与实际的太阳时有误差,最大误差达16分钟。

原因在于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治时间基于天文观测本身的缺陷,已经被原子钟报时的协调世界时(UTC)所取代。

国际原子时

国际原子时,TAI(来自法国名字Temps Atomique International)是根据以下秒的定义的一种国际参照时标, 属于国际单位制。

针对某些元素的原子能级跃迁频率有极高的稳定性,可采用基于铯原子(Cs 132.9)的能级跃迁原子秒作为时标。

1967年第13届国际计量大会上通过一项决议, 定义一秒为铯-133原子基态两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间。把在海平面实现的上述原子时秒,规定为国际单位制中的时间单位。

根据原子时秒的定义,任何原子钟在确定起始历元后,都可以提供原子时。由各实验室用足够精确的铯原子钟导出的原子时称为地方原子时。

TAI是1971年由国际时间局建立,现改为国际计量局(BIPM)的时间部门在维持,根据全球约60个实验室中的大约240台自由运转的原子钟提供的数据进行比较、综合,最后确定的原子时,称为国际原子时,简称TAI

TAI的起点是这样规定的:取1958年1月1日0时0分0秒世界时(UT)的瞬间作为同年同月同日0时0分0秒TAI。(事后发现,在该瞬间原子时与世界时的时刻之差为0.0039秒。这一差值就作为历史事实而保留下来。)

海拔高度,因为重力的不同,也会影响铯原子的速度….再详细的我就不继续讲了,毕竟我们是写代码的不是搞天文和物理的。

UTC

UTC 中文意思:协调世界时 、英语:Coordinated Universal Time,法语:Temps Universel Coordonné,由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC

UTC 是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。

协调世界时是世界上调节时钟和时间的主要时间标准,它与0度经线的平太阳时相差不超过1秒,并不遵守夏令时。

协调世界时是最接近格林威治标准时间(GMT)的几个替代时间系统之一。

对于大多数用途来说,UTC时间被认为能与GMT时间互换,但GMT时间已不再被科学界所确定。

由于地球自转速度的降低,自转一周的时间会变长,由此GMT的秒长也会变长,而原子时秒不会有改变,所以只采用原子时的话UTC总是会超过GMT的,两者之差逐年积累。

所以便采用跳秒(闰秒)的方法使协调时与世界时的时刻相接近,其差不超过1s。它既保持时间尺度的均匀性,又能近似地反映地球自转的变化。

按国际无线电咨询委员会(CCIR)通过的关于UTC的修正案,从1972年1月1日起UTC与UT1(在UT中加入极移改正得到)之间的差值最大可以达到±0.9s。位于巴黎的国际地球自转事务中央局负责决定何时加入闰秒。一般会在每年的6月30日、12月31日的最后一秒进行调整。

所以我们可以认为UTCGMT时间一样,因为UTC会改变自身去接近GMT,使其两者差距不会超过1秒。

夏令时

夏时制,另译夏令时间(英语:Summer time),又称日光节约时制、日光节约时间(英语:Daylight saving time),是一种为节约能源而人为规定地方时间的制度,在这一制度实行期间所采用的统一时间称为“夏令时间”。

一般在天亮较早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家规定不同。

中华人民共和国,当前不实行夏令时,当然历史上也实行过3次。

时区

地球是自西向东自转,东边比西边先看到太阳,东边的时间也比西边的早。东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算,这给人们带来不便。

为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议(又称国际子午线会议)上,规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为中时区(零时区)、东1-12区,西1-12区。

每个时区横跨经度15度,时间正好是1小时。最后的东、西第12区各跨经度7.5度,以东、西经180度为界。

每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时,相邻两个时区的时间相差1小时。

例如,中国东8区的时间总比泰国东7区的时间早1小时,而比日本东9区的时间晚1小时。

因此,出国旅行的人,必须随时调整自己的手表,才能和当地时间相一致。凡向西走,每过一个时区,就要把表拨慢1小时(比如2点拨到1点);凡向东走,每过一个时区,就要把表拨快1小时(比如1点拨到2点)。

并且规定英国(格林尼治天文台旧址)为本初子午线,即零度经线。

如果时间是以协调世界时(UTC)表示,则在时间后面直接加上一个“Z”(不加空格)。“Z”是协调世界时中0时区的标志。因此,“09:30 UTC”就写作“09:30Z”或是“0930Z”“14:45:15 UTC”则为“14:45:15Z”“144515Z”

UTC时间也被叫做祖鲁时间,因为在北约音标字母中用“Zulu”表示“Z”
时区可以用UTC偏移量形式表示:±[hh]:[mm]、±[hh][mm]、或者±[hh]。如果所在区时比协调世界时早1个小时(例如柏林冬季时间),那么时区标识应为“+01:00”“+0100”或者直接写作“+01”。这也同上面的“Z”一样直接加在时间后面。

"UTC+8"(北京时区)表示当协调世界时(UTC)时间为凌晨2点的时候,当地的时间为2+8点,即早上10点。

Unix时间戳

Unix时间戳(英文为Unix epoch,Unix time, POSIX timeUnix timestamp)是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

Unix时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z.

一个小时表示为Unix时间戳格式为:3600秒;一天表示为UNIX时间戳为86400秒,闰秒不计算。

在大多数的UNIX系统中UNIX时间戳存储为32位,这样会引发2038年问题或Y2038。

闰年

Shadow阅读(2470)

今天来聊一下闰年这个东西,记得最开始学编程的时候,就有个题是 写个程序判断给定的年份是否是闰年…

闰年是比普通年分多出一段时间的年分,在各种历法中都有出现,目的是为了弥补人为规定的纪年与地球公转产生的差异。

目前使用的格里高利历闰年规则如下:

  • 公元年分除以400可整除但除以3200不可整除,为闰年。
  • 公元年分除以4可整除但除以100不可整除,为闰年。
  • 公元年分除以4不可整除,为平年。
  • 公元年分除以100可整除但除以400不可整除,为平年。
  • 公元年分除以3200可整除,为平年。

每逢闰年,2月分有29日,平年的2月分为28日。

计算方法

if ((公元年分是400的倍数)或(公元年分是4的倍数但不是100的倍数))
{
  //闰年
} else
{
  //平年
}

产生原因

通常的解释是说一年有多少天多少小时多少分,取整数365还有多余的,累积达到一天24小时后,就多加一天的年是闰年。这个解释只是告诉了大家怎么计算,是人为设置的东西。

最根本的原因是:地球绕太阳运行周期为3655小时4846秒(合365.24219天)即一回归年(tropical year)。

公历的平年只有365日,比回归年短约0.2422 日,所余下的时间约为每四年累计一天,故第四年于2月末加1天(即2月29日),使当年的历年长度为366日,这一年就为闰年(1-12月分别为31天,29天,31天,30天,31天,30天,31天,31天,30天,31天,30天,31天)。

现行公历中每400年有97个闰年。按照每四年一个闰年计算,平均每年就要多算出0.0078天,这样经过四百年就会多算出大约3天来。因此每四百年中要减少三个闰年。所以公历规定:年份是整百数时,必须是400的倍数才是闰年;不是400的倍数的世纪年,即使是4的倍数也不是闰年。

因此,1977年为平年,1980年逢4的倍数为闰年,1900年逢100的倍数但非400的倍数故为平年,2000年逢400的倍数又为闰年。

需要注意的是,公历是根据罗马人的”儒略历”改编而得。由于当时没有了解到每年要多算出0.0078天的问题,从公元前46年,到16世纪,一共累计多出了10天。为此,当时的教皇格列高利十三世,将1582年10月5日人为规定为10月15日。并开始了新闰年规定。

此外,如依照现有太阳年的长度与上述闰年规则,由于地球的自转速度逐渐降低,而公转速度则相对更加稳定,所以上述的系统经过更长的周期也会发生微小的误差。每8000年又约差一日,因此约翰·赫歇尔(John Herschel)提议每逢4000的倍数不闰,如公元4000年。但距此年分来临尚有约二千年之遥,因此还未曾真正纳入规则或实施过。又由于地球公转速度的不稳定与众多影响因素,届时是否需要纳入此规则有待商榷。

公元前的闰年

公元前之闰年出现在前1, 前5, 前9, 前13, ...,或记作1 BC,5 BC,9 BC,13 BC,...,或在数轴上记作0,-4,-8,-12,...。

判断是否闰年,须将年份值减1再以“除以4”计算,或以数轴记法表示时直接计算(正负性不影响是否整除)。

(因为没有公元0年这一年(除非临时约定,并注明对应等式),所以公元前1, 2, 3, 4, … 年应该在数学数轴上对应着(但不是,或不应该在历法上称)公元0, -1, -2, -3, … 年,而公元前1, 5, 9, 13, … 年在数学数轴上对应着0, -4, -8, -12, … 年,为4的倍数)。 记住:临时约定的数学“0”年,等于天文学固有的“0”年,等于历法公元前一年。

公元0年

阳历中的“闰年”

阳历中有闰日的年分叫闰年,相反就是平年,平年为365天,闰年为366天。在公历儒略历及纪年中,平年的二月为28天,闰年的二月为29天。闰年平月2月29日为闰日。

1950-2050年间的闰年:

1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000
,2004,2008,2012,2016,2020,2024,2028,2032,2036,2040,2044,2048.

中国农历的“闰年”

中国旧历农历作为阴阳历的一种,每月的天数依照月亏而定,一年的时间以12个月为基准,平年比一回归年少约11天。

为了合上地球围绕太阳运行周期即回归年,每隔2到4年,增加一个月,增加的这个月为闰月。有闰月的一年称为闰年一年13个月。闰月加到哪个月,以农历历法规则推断,主要依照与农历的二十四节气相符合来确定。

一般年分为12个月,353(罕见)或354(多见)或355(少见)天,闰年则为13个月,383(少见)或384(多见)或385(罕见)天。

如1984年鼠年的农历中,有两个十月,通常成为前十月和后十月(即闰月)。农历闰年闰月的推算,3年一闰,5年二闰,19年七闰;农历基本上19年为一周期对应于公历同一时间。如公历的2001年5月27日、1982年5月27日和1963年5月27日这个日子,都是闰四月初五。

超长农历年

最长的农历闰月年份的天数可长达385天,这样的农历闰月年份是很罕见的。从公元前221年至公元1900年的2120年里,一共只有9次。

从公元1900年至公元4000年这2100年里出现了22次,出现的年份有1925年、1944年、2006年、2270年、2289年、2351年、2606年、2625年、2634年、2889年、2951年、2970年、3234年、3253年、3296年、3315年、3589年、3608年、3872年、3915年、3934年、3953年。平年超短农历年只有353天,公示元年至公元5000年之间,农历年有353天的年份只有以下9个:
780年、1620年、1965年、2372年、3620年、3903年、3965年、4186年、4248年。

公历1982年至2042年与农历闰年闰月对照表:

1982年5月23日 闰四月小 壬戊年 2014年10月24日 闰九月小 甲午年
1984年11月23日 闰十月小 甲子年 2017年7月23日 闰六月大 丁酉年
1987年7月26日 闰六月小 丁卯年 2020年5月23日 闰四月小 庚子年
1990年6月23日 闰五月小 庚午年 2023年3月22日 闰二月小 癸卯年
1993年4月22日 闰三月小 癸酉年 2025年7月25日 闰六月小 乙巳年
1995年9月25日 闰八月小 乙亥年 2028年6月23日 闰五月小 戊申年
1998年6月24日 闰五月小 戊寅年 2031年4月22日 闰三月小 辛亥年
2001年5月23日 闰四月小 辛巳年 2033年8月25日 闰冬月小 癸丑年
2004年3月21日 闰二月小 甲申年 2036年7月23日 闰六月大 丙辰年
2006年8月24日 闰七月小 丙戊年 2039年6月22日 闰五月小 己未年
2009年6月23日 闰五月小 己丑年 2042年3月22日 闰二月小 壬戊年
2012年5月21日 闰四月小 壬辰年

附部分语言闰年判断:

C/C++:

if ((year % 100 != 0) && (year % 4 == 0) || (year % 400 == 0)) {
   // 闰年;
} else {
   // 平年;
}
#define ISLEAP(yr) ((!((yr) % 4) && (yr) % 100) || !((yr) % 400))

C#语言:

/// <summary>
/// 判断指定年份是否为闰年
/// </summary>
/// <param name="year">年份</param>
/// <returns>返回布尔值true为闰年,反之不是</returns>
public static bool isLeapYear(int year)
{
return ((year % 4 == 0 && year % 100 != 0) ||year%400==0);
}

Java语言:

import java.util.Scanner;
public class LeapYear {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("请输入年份:");
        int year = input.nextInt();

        if((year % 4 == 0 && year % 100 != 0) || year % 400 ==0)
            System.out.print(year + "年是闰年。");
        else 
            System.out.print(year + "年不是闰年。");
    }
}

Python 语言:

# -*- coding: cp936 -*-
temp = input("输入年份:")
YEAR = int(temp)
if (YEAR % 4 == 0 and YEAR % 100 != 0) or YEAR % 400 == 0:    
    print ("闰年")
else:
    print ("非闰年")

C++语言:

#include<iostream>
int main()
{
    int year;
    std::cout<<"请输入年份:";
    std::cin>>year;             //输入待判断年份,如2008
    std::cout<<year<<(((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) == 1 ? "年是闰年" : "年是平年")<<std::endl;
    return 0;
}

C语言:

#include <stdio.h>
int main(void)
{
    int y;
    printf("请输入年份,回车结束\n");
    scanf("%d",&y);
    if((y%4==0&&y%100!=0)||y%400==0)
        printf("%d是闰年\n",y);
    else
        printf("%d是平年\n",y);
    return 0;
}

Bash/Shell:

year=$1
if [ "$(( $year % 4 ))" == "0" ] && [ "$(( $year % 100 ))" != "0" ] || [ "$(( $year % 400 ))" == "0" ]
then
    echo "leap year"
else
    echo "common year"
fi

Erlang语言:

-module(year).
-export([isLeap/1]).
isLeap(Year) ->
    if Year rem 400 == 0 ->
        true;
    Year rem 100 == 0 ->
        false;
    Year rem 4 == 0 ->
        true;
    true ->
        false
    end.

Ecmascript语言:

// 判断指定年份是否为闰年
function isleap(){
var the_year = new Date().getFullYear();
var isleap = the_year % 4 == 0 && the_year % 100 !=0 || the_year % 400 ==0;
return isleap;
}

VB语言:

Public Function isLeapYear(year As Integer) As Boolean
isLeapYear = (year Mod 4 = 0 And year Mod 100 <> 0) Or year Mod 400 = 0
End Function

MATLAB语言:

function lpflag = isleapyear(year)
% 判断是否为闰年
% Input  -year 年份,数值
% Output -lpflag lpflag = 1,闰年;lpflag = 0,平年
lpflag = (~mod(year, 4) && mod(year, 100)) || ~mod(year, 400);

shell命令的执行方式

Shadow阅读(2644)

Shell有两种执行命令的方式:

  • 交互式(Interactive):解释执行用户的命令,用户输入一条命令,Shell就解释执行一条。
  • 批处理(Batch):用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。

这里再讲一下Shell 脚本的运行方式:

  • 通过文件名执行 : shell脚本可以直接通过文件名执行,需要注意的是文件需要执行权限并且设置shebang(关于shebang的解释请看这里shebang)。通过 sudo chmod +x ./file_name.sh 来给文件添加执行权限;
  • 指定脚本解释器来执行文件 : 我们常用的 sh file_name.sh 就是指定了脚本解释器 /bin/sh来解释执行脚本;这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用;常见的脚本解释器还有:/bin/bash等,我们可以使用ls -l /bin/*sh命令来查看当前可用的脚本解释器;
  • 使用source命令执行脚本 : 这种方式不会像前两种方式一样fork一个子进程去执行脚本,而是使用当前shell环境执行,用于 .bashrc或者.bash_profile被修改的时候,我们不必重启shell或者重新登录系统,就能使当前的更改生效。

深度探索C++对象模型前言

Shadow阅读(2746)

读者对象

就像书中导读所说,读者对象不是面向新手的教程,而是写给有一定C++基础的人看的。

C++老手分为两类:一种是把语言用的烂熟,OO观念也有;另一种人不但如此,还对于台下的机制,如编译器合成的defaultconstructorobject 的内存布局等有莫大的兴趣。

对于第二种人,探索对象模型的乐趣不言而喻。至于第一类人,了解C++对象模型,绝对有助于你在语言及面向对象观念两方面的层次提升。

你需要细细推敲每一个句子,每一个例子,囫囵吞枣是完全没用的。

作者LippmanC++大师级人物,并且参与了第一套C++编译器的开发,他的解说鞭辟入里。

在研读完大师的讲解之后,我也尝试以一种更加清晰易懂的方式将其写出来讲出来,再结合不同IDE做一些测试,希望能帮到更多的人理解C++对象模型。

对象模型

有两个概念可以解释C++对象模型
1. 语言中直接支持面向对象程序设计的部分
2. 对于各种支持的底层实现机制

语言层面的支持,在大多数的C++介绍中都能找到,至于第二个概念就是lippmaninside the c++ object model中所介绍的。

C++对象模型的第一概念是一种“不变量”。例如,C++ classvirtual function在编译时期就固定下来了,程序员没有办法在执行期动态的添加或取代其中的某一个。这使得virtual操作调用得以快速的dispatch (指派)结果,付出的成本则是执行期的弹性。

对象模型的底层实现机制,在语言层面是看不出来的,而且C++标准对于编译器如何实现,在某些方面上是没有约束的。所以大多数决定都是编译器自己做取舍。

比如 virtual function call,一般而言都是通过一个表格(内含virtual function的地址,通常称之为虚函数表)的索引而决议的。

但是一定要通过表格实现?当然并不是必须的,编译器完全可以自己引进其他变通做法。不过目前几乎所有编译器的实现都是基于虚函数表的,并且在程序执行前就已经构造完毕。

那么既然对于C++的底层实现机制并未标准化,那么何必要探讨它呢?

主要的理由是,如果一个程序员了解底层实现模型,便能写出效率较高的代码,当然仁者见仁智者见智,探索对象模型带来的好处每个人都有不同的感悟,但是我相信你一定不会后悔。

因此,我要大声的说:“有经验的C++ programmer 都应该看一下对象模型”

Hello World

Shadow阅读(3063)

Hello World

谨以此文献给Hello World

C

#include <stdio.h>  
int main()                #main 入口函数  
{  
  printf("Hello,World!"); #printf 函数打印  
  return 1;               #函数返回值  
}  

C++

#include <iostream>               //std::cout 要用到的头文件  
#include <stdio.h>                //标准输入输出头文件  

int main()  
{  
  printf("Hello,World!--Way 1\n");    //printf 语句打印  
  puts("Hello,World!--Way 2");        //puts 语句  
  puts("Hello," " " "World!--Way 3"); //字符串拼接  
  std::cout << "Hello,World!--Way 4" << std::endl; //C++ 教科书上写法  
  return 1;                                        //作为注释  
} 

C#

//FileName: HelloWorld.cs  
using System;  
class TestApp  
{  
  public static void Main()  
  {  
    Console.WriteLine("Hello,World!");  
    Console.ReadKey();  
  }  
}  

JAVA

#FileName: HelloWorld.java  
public class HelloWorld   #如果有 public 类的话,类名必须和文件同名,注意大小写  
{  
  #Java 入口程序,程序从此入口  
  public static void main(String[] args)  
  {  
  #向控制台打印一条语句  
    System.out.println("Hello,World!");  
  }  
}  

Python

print "Hello,World!"   #Python 2.x  

print("Hello,World!")  #Python 3.x   

PHP

<?php  
echo "Hello,World!";            //打印语句  
echo "The first php program!";  //打印语句  
echo phpinfo();                 //phpinfo()系统函数,输出环境信息  
?>  

JavaScript

var sys = require("sys");    #导入需要的 sys 模块  
sys.puts("Hello,World!");    #调用里面的 puts 函数来打印字符串  

SQL

select 'Hello,World!' from xxx;

Shell

#安装了MinGW和MSYS的Windows平台
D:\HelloWorld>echo "Hello,World!"
"Hello,World!"
#Linux平台下
#echo "Hello,World!"   或 printf "Hello,World!" 
#如果是写在文件中:
chmod +x  HelloWorld.sh
./HelloWorld.sh

Ruby

#可用 print 语句打印
print "Hello,World!\n"
#可用 puts 语句打印
puts  "Hello,World!\n"
#可以先声明一个变量,然后再用 puts 语句
a = "Hello,World!\n"
puts a
#可以先写个函数再调用
def say(name)
   "Hello,#{name}"
end  
puts say("World!")

R

C:\>R                  #安装好了之后,输入 R 后显示

R version 3.1.2 (2014-10-31) -- "Pumpkin Helmet"
Copyright (C) 2014 The R Foundation for Statistical Computing
Platform: i386-w64-mingw32/i386 (32-bit)

R

'license()''licence()'

R.
'contributors()'
'citation()'RR

'demo()''help()'
'help.start()'HTML
'q()'R.

GO

// Hello world in Go

package main
import "fmt"
func main() {
 fmt.Printf("Hello World\n")
}

Perl

#!C:\Perl\bin                    #Windows 平台下
#!/usr/bin/env perl              #Linux 环境下
print "Hello,World!\n";          #print("Hello,World") 也可

HTML

<!DOCTYPE html>  
<html>  
<body>  
<h1>This is the first program!</h1>  
<p>Hello,World!</p>  
</body>  
</html>

Scala

object HelloWorld
{
  def main(args:Array[String])
  {
     println("Hello,World!");
  }
}
//编译
d:\HelloWorld>scala HelloWorld.scala
Hello,World!

Pascal

Program HelloWorld(output);  
begin  
  writeln('Hello, world!') 

 {程序块的最后一条语句后不需要";" - 如果添加一个";",会在程序中增加一个“空语句”}  
end.

Objective-c

/* Hello World in Objective-C.
** Since the standard implementation is identical to K&R C,
** a version that says hello to a set of people passed on
** the command line is shown here.
*/

#include <stdio.h>
#include <objpak.h>
int main(int argc,char **argv)
{
    id set = [Set new];
    argv++;while (--argc) [set add:[String str:*argv++]];
    [set do:{ :each | printf("hello, %s!\n",[each str]); }];
    return 0;
}

Swift

// Hello world in Swift

println("Hello, world!")

参考文献:https://helloworldcollection.github.io/

游戏 && 后端

传送门传送门