5.5 例题:时区间时间的转换

问题描述

直到 19世纪,时间校准是一个纯粹的地方现象。每一个村庄当太阳升到昀高点的时候把他们的时钟调到中午 12点。一个钟表制造商人家或者村里主表的时间被认为是官方时间,市民们把自家的钟表和这个时间对齐。每周一些热心的市民会带着时间标准的表,游走大街小巷为其他市民对表。在城市之间旅游的话,在到达新地方的时候需要把怀表校准。但是,当铁路投入使用之后,越来越多的人频繁地长距离地往来,时间变得越来越重要。在铁路的早期,时刻表非常让人迷惑,每一个所谓的停靠时间都是基于停靠地点的当地时间。时间的标准化对于铁路的高效运营变得非常重要。

在 1878年,加拿大人 Sir Sanford Fleming 提议使用一个全球的时区(这个建议被采纳,并衍生了今天我们所使用的全球时区的概念),他建议把世界分成 24个时区,每一个跨越 15度经线(因为地球的经度 360度,划分成 24块后,一块为 15度)。Sir Sanford Fleming的方法解决了一个全球性的时间混乱的问题。

美国铁路公司于 1883年 11月 18日使用了 Fleming 提议的时间方式。 1884年一个国际子午线会议在华盛顿召开,他的目的是选择一个合适的本初子午线。大会昀终选定了格林威治为标准的 0度。尽管时区被确定了下来,但是各个国家并没有立刻更改他们的时间规范,在美国,尽管到 1895年已经有很多州开始使用标准时区时间,国会直到 1918年才强制使用会议制定的时间规范。

今天各个国家使用的是一个 Fleming时区规范的一个变种,中国一共跨越了 5个时区,但是使用了一个统一的时间规范,比 Coordinated Universal Time(UTC,格林威制时间)早 8个小时。俄罗斯也拥护这个时区规范,尽管整个国家使用的时间和标准时区提前了 1个小时。澳大利亚使用 3个时区,其中主时区提前于他按 Fleming规范的时区半小时。很多中东国家也使用了半时时区(即不是按照 Fleming的 24个整数时区)。

因为时区是对经度进行划分,在南极或者北极工作的科学家直接使用了 UTC时间,否则南极大陆将被分解成 24个时区。

时区的转化表如下:

UTC Coordinated Universal Time

GMT Greenwich Mean Time, 定义为 UTC

BST British Summer Time, 定义为 UTC+1 hour

IST Irish Summer Time, 定义为 UTC+1 hour 

WET Western Europe Time, 定义为 UTC

WEST Western Europe Summer Time, 定义为 UTC+1 hour 

CET Central Europe Time, 定义为 UTC+1 

CEST Central Europe Summer Time, 定义为 UTC+2 

EET Eastern Europe Time,定义为 UTC+2 

EEST Eastern Europe Summer Time, 定义为 UTC+3 

MSK Moscow Time, 定义为 UTC+3

MSD Moscow Summer Time, 定义为 UTC+4

AST Atlantic Standard Time, 定义为 UTC-4 hours

ADT Atlantic Daylight Time, 定义为 UTC-3 hours

NST Newfoundland Standard Time, 定义为 UTC-3.5 hours 

NDT Newfoundland Daylight Time, 定义为 UTC-2.5 hours 

EST Eastern Standard Time, 定义为 UTC-5 hours

EDT Eastern Daylight Saving Time, 定义为 UTC-4 hours 

CST Central Standard Time, 定义为 UTC-6 hours

CDT Central Daylight Saving Time, 定义为 UTC-5 hours 

MST Mountain Standard Time, 定义为 UTC-7 hours 

MDT Mountain Daylight Saving Time, 定义为 UTC-6 hours 

PST Pacific Standard Time, 定义为 UTC-8 hours 

PDT Pacific Daylight Saving Time, 定义为 UTC-7 hours 

HST Hawaiian Standard Time, 定义为 UTC-10 hours

AKST Alaska Standard Time, 定义为 UTC-9 hours

AKDT Alaska Standard Daylight Saving Time, 定义为 UTC-8 hours 

AEST Australian Eastern Standard Time, 定义为 UTC+10 hours

AEDT Australian Eastern Daylight Time, 定义为 UTC+11 hours

ACST Australian Central Standard Time, 定义为 UTC+9.5 hours

ACDT Australian Central Daylight Time, 定义为 UTC+10.5 hours 

AWST Australian Western Standard Time, 定义为 UTC+8 hours

下面给出了一些时间,请在不同时区之间进行转化。输入数据输入的第一行包含了一个整数 N,表示有 N组测试数据。接下来 N行,每一行包

括一个时间和两个时区的缩写,它们之间用空格隔开。时间由标准的 a.m./p.m给出。

midnight表示晚上 12点(12:00 a.m.),noon表示中午 12点(12:00 p.m.)。

输出要求

假设输入行给出的时间是在第一个时区中的标准时间,要求输出这个时间在第二个时区中的标准时间。

输入样例

noon HST CEST

11:29 a.m. EST GMT

6:01 p.m. CST UTC

12:40 p.m. ADT MSK

输出样例

midnight

4:29 p.m.

12:01 a.m.

6:40 p.m.

解题思路

这个题目要求在两个时区之间进行时间的转换。我们根据每个时区与格林威治时间的转换公式可以推算出两个时区之间的差别。问题的解决方法不难想到,只是日期处理类问题具有共同的特点就是输入输出比较麻烦,有一些需要特殊处理的情况,例如转换后多出一天或少了一天的情况需要处理。具体到这个题目来说:输入时,除了一般的时间表示法:时:分

a.m/p.m.之外,要特殊处理 noon和 midnight;在直接通过格林威治时间进行转换后,要判断是否超过一天或减少了一天的情况;在输出时间时,要对 noon和 midnight进行特殊处理。

解决这个问题时,关键的是确定两个时区之间的时差。因为时区是用字符串形式给出的,所以要先将时区对应到该时区与格林威治时间的时差上。有了每个时区与格林威治时间的时差,就可以计算任意两个时区之间的时差。

参考程序

#include <iostream>
#include <string>

int difference(char* zone1, char* zone2){ //计算两个时区之间的时差,以分钟为单位。

char* zone[32]={"UTC",

  "GMT","BST","IST","WET","WEST",

  "CET","CEST","EET","EEST","MSK",

  "MSD","AST","ADT","NST","NDT",

  "EST","EDT","CST","CDT","MST",

  "MDT","PST","PDT","HST","AKST",

  "AKDT","AEST","AEDT","ACST","ACDT",

  "AWST"};

 float time[32]={0,0,1,1,0,1,1,2,2,3,3,4,-4,-3,-3.5,-2.5,-5,-4,-6,-5,-7,

 -6,-8,-7,-10,-9,-8,10,11,9.5,10.5,8};

 int i, j;

 for (i = 0; strcmp(zone[i], zone1); i++); //找到第一个时区对应的位置

 for (j = 0; strcmp(zone[j], zone2); j++); //找到第二个时区对应的位置

 return (int)((time[i] - time[j]) * 60); //计算并返回时差,以分钟为单位

 }

int main()

 {

 int nCases;

 scanf("%d", &nCases); // 读入测试数据数目

 for (int i = 0; i < nCases; i++){ // 对每组输入数据

  char time[9]; //输入的时间

  int hours, minutes; //转换成整数

  scanf("%s", time); //读入时间

  switch(time[0]){

 case 'n': hours = 12; //输入为 ”noon”

 minutes = 0;

 break;

 case 'm': hours = 0; //输入为 ”midnight”

 minutes = 0;

 break;

   default : sscanf(time, "%d:%d", &hours, &minutes); //输入为时:分

 hours %= 12;

  scanf("%s", time);  //读入 “a.m.或 p.m.”

  if (time[0] == 'p') hours += 12;

 }

  char timezone1[5], timezone2[5];

  scanf("%s%s", timezone1, timezone2); //读入时区

 int newTime;  //以分钟为单位

 newTime = hours * 60 + minutes + difference(timezone2, timezone1);

 if (newTime < 0) newTime += 1440; //提前一天,将负的时间加上一天。

 newTime %= 1440;  //如果超过一天,将一天的时间减去。

  switch(newTime){

   case 0 : printf("midnight\n"); //新时间为凌晨

 break;

   case 720: printf("noon\n"); //新时间为中午

 break;

 default : hours = newTime / 60; //新时间的时

  minutes = newTime % 60; //新时间的分

  if(hours == 0) //凌晨, 分不为 0

 printf("12:%02d a.m.\n", minutes);

  else if(hours < 12) //上午

 printf("%d:%02d a.m.\n", hours, minutes);

 else if(hours == 12) //中午, 分不为 0

 printf("12:%02d p.m.\n", minutes);

  else //下午

 printf("%d:%02d p.m.\n", hours%12, minutes);

 } // end of switch

 } //end of for

system("pause");
return 0;
 } // end of main

 

实现中常见的问题

问题一:有人在处理时区名称和时差的对应关系时,不会用数组元素及其下标的方法处理,而是用一连串的 if else语句逐一判定,造成代码冗余,增大了出错的机会;

问题二:对特殊时间点的表示有理解上的问题。12:01am表示凌点 1分,12:01pm表示中午 12点 1分;中午输出 noon,凌晨输出 midnight;

问题三:向前走了一天和推后了一天的情况没考虑到。

问题四:大同学将 12小时制换算成 24小时制,然后根据时区关系作时间变换,再由24小时制换算成 12小时制,注意当有半个小时的差别时,分钟的数值的调整昀容易出错。

posted on 2010-04-14 13:35  蓝牙  阅读(482)  评论(0编辑  收藏  举报