B - Moscow Time(4.7.2)

/*
Description
In e-mail the following format for date and time setting is used:

EDATE::=Day_of_week, Day_of_month Month Year Time Time_zone


Here EDATE is the name of date and time format, the text to the right from ``::=" defines how date and time are written in this format. Below the descriptions of EDATE fields are presented:

Day-of-week

The name of a day of the week. Possible values: MON, TUE, WED, THU, FRI, SAT, SUN. The name is followed by ``," character (a comma).

Day-of-month

A day of the month. Set by two decimal digits.

Month

The name of the month. Possible values: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC.

Year

Set by two or four decimal digits. If a year is set by two decimals it is assumed that this is a number of the year of the XX century. For instance, 74 and 1974 set a year of 1974.

Time

Local time in format hours:minutes:seconds, where hours, minutes and seconds are made up of two decimal digits. The time keeps within the limits from 00:00:00 to 23:59:59.

Time-zone

Offset of local time from Greenwich mean time. It is set by the difference sign ``+" or ``-"and by sequence of four digits. First two digits set the hours and the last two the minutes of offset value. The absolute value of the difference does not exceed 24 hours. Time zone can also be presented by one of the following names:

Name Digital value


UT   -0000

GMT  -0000

EDT  -0400

CDT  -0500

MDT  -0600

PDT  -0700


Each two adjacent fields of EDATA are separated with exactly one space. Names of day of the week, month and time zone are written in capitals. For instance, 10 a.m. of the Contest day in St.Petersburg can be presented as

TUE, 03 DEC 96 10:00:00 +0300

Write a program which transforms the given date and time in EDATE format to the corresponding date and time in Moscow time zone. So called ``summer time" is not taken into consideration. Your program should rely on the predefined correctness of the given Day-of-week and Time-zone.

A note

Moscow time is 3 hours later than Greenwich mean time (time zone +0300)
Months: January, March, May, July, August, October and December have 31 days. Months: April, June, September and November have 30 days. February, as a rule, has 28 days, save for the case of the leap year (29 days).

A year is a leap year if valid one out of two following conditions:
its number is divisible by 4 and is not divisible by 100;
its number is divisible by 400.
For instance, 1996 and 2000 are the leap years, while 1900 and 1997 are not.

Input
Input contains date and time in EDATE format in the first line. Minimum permissible year in the input data is 0001, maximum - 9998. Input EDATA string does not contain leading and trailing spaces.

Output
Output must contain a single line with date and time of Moscow time zone in EDATE format. In output EDATE string a Year can be presented in any of the two allowed ways. The output string should not include leading and trailing spaces.

Sample Input

MON, 23 JUL 1987 23:23:45 EDT
TUE, 03 DEC 1996 09:30:00 +0300
WED, 28 FEB 1987 23:23:45 -2112
SUN, 31 JUL 1987 23:23:45 -0204
WED, 28 FEB 01 23:23:45 +0103
WED, 28 FEB 1700 23:23:45 +0103
THU, 01 JUL 2001 00:23:45 +0503
WED, 28 FEB 1880 23:23:45 +0103
MON, 01 JAN 2000 00:01:45 UT
FRI, 01 MAR 2000 00:23:45 +0503
MON, 31 DEC 2001 00:23:45 -0503
MON, 01 JAN 2001 00:23:45 +0503
MON, 31 DEC 2001 23:23:45 +0103
MON, 31 DEC 0002 00:23:45 +0503
SAT, 31 DEC 2001 23:23:45 +0220

Sample Output(两种形式中的一种)

TUE, 24 JUL 1987 06:23:45 +0300
TUE, 24 JUL 87 06:23:45 +0300

TUE, 03 DEC 1996 09:30:00 +0300
TUE, 03 DEC 96 09:30:00 +0300

THU, 01 MAR 1987 23:35:45 +0300
THU, 01 MAR 87 23:35:45 +0300

MON, 01 AUG 1987 04:27:45 +0300
MON, 01 AUG 87 04:27:45 +0300

**THU, 01 MAR 1901 01:20:45 +0300
**THU, 01 MAR 01 01:20:45 +0300

THU, 01 MAR 1700 01:20:45 +0300
THU, 01 MAR 1700 01:20:45 +0300

WED, 30 JUN 2001 22:20:45 +0300
WED, 30 JUN 2001 22:20:45 +0300

THU, 29 FEB 1880 01:20:45 +0300
THU, 29 FEB 1880 01:20:45 +0300

MON, 01 JAN 2000 03:01:45 +0300
MON, 01 JAN 2000 03:01:45 +0300

THU, 29 FEB 2000 22:20:45 +0300
THU, 29 FEB 2000 22:20:45 +0300

MON, 31 DEC 2001 08:26:45 +0300
MON, 31 DEC 2001 08:26:45 +0300

SUN, 31 DEC 2000 22:20:45 +0300
SUN, 31 DEC 2000 22:20:45 +0300

TUE, 01 JAN 2002 01:20:45 +0300
TUE, 01 JAN 2002 01:20:45 +0300

SUN, 30 DEC 0002 22:20:45 +0300
SUN, 30 DEC 0002 22:20:45 +0300

SUN, 01 JAN 2002 00:03:45 +0300
SUN, 01 JAN 2002 00:03:45 +0300


*/
/*
这道题纠结了我老半天,花了将近一天的功夫才把它AC,去网上找也没几个人做。郁闷。各种漏洞百出,
各种错误都出现了,一点一点调试才得到了正确答案。
这道题我认为考察的就是逻辑思维的判断,对字符串的处理。没有什么高明的算法,没有什么难度。就是太麻烦。
不仔细很容易出问题。
解析:
    这道题就是将EDATE的时间转换成墨西哥时间而已。题目简单,但却很复杂。
    其中各个方面都要考虑到了,考虑周全了才行。还得需要同学的帮助,因为出错了有时你并不知道哪里出了错。
    多找几个人帮你查查错,会有很大的帮助。
    输入有两种形式:一种是MON, 23 JUL 1987 23:23:45 EDT这种形式,另一种是TUE, 03 DEC 1996 09:30:00 +0300
    这种形式,必须都要考虑到。
    再就是注意时间转换的问题其实他是这么算的:
    比如:输入时区是 -2112
    参与运算的应该是 -2112-0300;将其中的时和分分离出来就是 dh = -24 dm = 12  (符号为)ch = '-'(与输入的正负相同)
    再比如:输入时区为 +0503
    参与运算的应该是 -(0503- 0300);将其中的时和分分离出来就是 dh = -2 dm = 03 (符号为)ch = '+'(与输入的正负相同)
    又如:输入时区为 +0103
    参与运算的应该是 +0300-0103;将其中的时和分分离出来就是 dh = +2 dm = -03 但是后面用到的时当ch为+时minute-=dm
                    符号为负时minute += dm;这就起到了正负号的作用,如果dm也带着正负号的话,则应该做相应的变化
                    为了避免这种思维上的混乱,我们在处理数据之前就把时和分分离出来将dm保存了,然后单独进行dh的加减判断
    再比如:输入时区为 GMT
    此时,就不同于上面的运算方式了,应该按照下面的表来操作
    Name Digital value


    UT   -0000

    GMT  -0000
    
    EDT  -0400

    CDT  -0500

    MDT  -0600

    PDT  -0700
    相应的转化为数字信息,对应的有 UT dh = +3; GMT dh = +3; EDT dh = +7;
    CDT dh = +8; MDT dh = +9; PDT dh = +10; dm = 0;
    这样理清了转换操作就不难了,接下来就是要注意对minute hour day year month week的处理了,
    牵一发而动全身,一定要谨慎处理。

*/


#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <iomanip>
using namespace std;
bool isLeapYear( int year )
{
    if( year % 400 == 0 || ( year % 4 == 0 && year % 100 != 0 ) )
        return 1;
    else
        return 0;
}
int main()
{
    int week, day, month, year, hour, minute, second, dh, dm;
    char w[4], mth[4], zt[6], y[5], ch;    //开始我设的数组长度都是3,可是运行却出错了,w的值总是读不进去。
                                    //调试了老半天仍然有错,最后在同学的帮助下,发现当输入mth时,w的值没有了。
                                    //w的值哪里去了呢?我们怀疑是缓冲区的问题,w的数组太小了,导致输入字符时数组越界。
                                    //然后数组长度改为4,成功解决了问题。
    while( cin.get( w, 4, ',') )
    {
        cin.get();
        //cout << w << endl;
        cin >> day >> mth;
        //cin.get();
        cin >> y;
        cin >> hour >> ch >> minute >> ch >> second;
        cin >> zt;
        cin.get();    //调试半天都不知道哪里有错,总是再第二组数据测试时出错,后来找到问题,
                        //第一次输入数据后有个回车没有消掉,导致第二次读取时将回车读入w数组,而后面的字符没有读入,
                        //导致后面的所有数据读取出错。感谢我的同学帮我找出了错误。
        if( ( strlen( y ) ) == 2 )   //对输入的年份进行判断;将输入的四位、二位年份转化为四位的年份
            year = 1900 + ( y[0] - '0' + 0 ) * 10 + ( y[1] -'0' + 0 );
        else if( ( strlen( y ) ) == 4 )
            year = ( y[0] - '0' + 0 ) * 1000 + ( y[1] - '0' + 0 ) * 100 
                    + ( y[2] - '0' + 0 ) * 10 + ( y[3] - '0' + 0 );
        
        //将星期几的字符串转化成相应的数字信息,便于处理。
        
        week = -1;  //初始化week=-1
        if( strcmp( w, "MON" ) == 0 )
            week = 1;
        if( strcmp( w, "TUE" ) == 0 )
            week = 2;
        if( strcmp( w, "WED" ) == 0 )
            week = 3;
        if( strcmp( w, "THU" ) == 0 )
            week = 4;
        if( strcmp( w, "FRI" ) == 0 )
            week = 5;
        if( strcmp( w, "SAT" ) == 0 )
            week = 6;
        if( strcmp( w, "SUN" ) == 0 )
            week = 0;
        //cout << week << endl;
        
        //对dh dm的处理转换
        dh = dm = 0;    //初始化默认为0
        ch = '+';       //初始化默认为+
        if( strcmp( zt, "UT" ) == 0 )
            dh = +3;
        else if( strcmp( zt, "GMT" ) == 0 )
            dh = +3;
        else if( strcmp( zt, "EDT" ) == 0 )
            dh = +7;
        else if( strcmp( zt, "CDT" ) == 0 )
            dh = +8;
        else if( strcmp( zt, "MDT" ) == 0 )
            dh = +9;
        else if( strcmp( zt, "PDT" ) == 0 )
            dh = +10;
        else
        {
            ch = zt[0];
            dh = ( zt[1] - '0' + 0 ) * 10 + ( zt[2] - '0' + 0 );
            dm = ( zt[3] - '0' + 0 ) * 10 + ( zt[4] - '0' + 0 );
            //cout << ch << ' ' << dh << ' ' << dm << endl;
            if( ch == '+' )
            {
                if( dh >= 3 )
                    dh = - ( dh - 3 ) ;
                else if( dh < 3 )
                    dh = 3 - dh;
            }
            else if( ch == '-' )
                dh = - ( dh + 3 );
        }
        //cout << ch << ' ' << dh << ' ' << dm << endl;
        
        //将相应的zt时区字符串转换为+0300(墨西哥时区)
        strcpy( zt, "+0300\0" );
        
        //将输入的mth月份字符串转换为数字信息,以便于后面的处理
        if( strcmp( mth, "JAN" ) == 0 )
            month = 1;
        if( strcmp( mth, "FEB" ) == 0 )
            month = 2;
        if( strcmp( mth, "MAR" ) == 0 )
            month = 3;
        if( strcmp( mth, "APR" ) == 0 )
            month = 4;
        if( strcmp( mth, "MAY" ) == 0 )
            month = 5;
        if( strcmp( mth, "JUN" ) == 0 )
            month = 6;
        if( strcmp( mth, "JUL" ) == 0 )
            month = 7;
        if( strcmp( mth, "AUG" ) == 0 )
            month = 8;
        if( strcmp( mth, "SEP" ) == 0 )
            month = 9;
        if( strcmp( mth, "OCT" ) == 0 )
            month = 10;
        if( strcmp( mth, "NOV" ) == 0 )
            month = 11;
        if( strcmp( mth, "DEC" ) == 0 )
            month = 12;
        //cout << month << endl;
        
        //对小时和分钟的调整
        
        if( ch == '+' )
        {
            hour += dh;
            minute -= dm;
        }
        else
        {
            hour -= dh;
            minute += dm;
        }
        
        //对时间和日趋的规整,防止越界。
        //下面对分钟进行规整
        if( minute >= 60 )
        {
            hour += minute / 60;
            minute %= 60;
        }
        else if( minute < 0 )
        {
            minute += 60;
            hour--;
        }
        //下面对小时进行规整
        if( hour >= 24 )
        {
            day += hour / 24;
            week = ( week + 1 ) % 7;
            hour %= 24;
        }
        else if( hour < 0 )
        {
            day--;
            hour += 24;
            week = ( week - 1 + 7 ) % 7;
        }
        //下面对日期进行规整
        if( day > 31 && ( month == 1 || month == 3 || month == 5 || month == 7
                         || month == 8 || month == 10 || month == 12 ) )
            month++, day %= 31;
        else if( day > 30 && ( month == 4 || month == 6 || month == 9 || month == 11 ) )
            month++, day %= 30;
        else if( day > 28 && month == 2 )
        {
            if( isLeapYear( year ) )
            {
                if( day > 29)
                    month++, day %= 29;
            }
            else
                month++, day %= 28;
        }
        else if( day < 1 )
        {
            month--;   //先进行month减一操作,判断需要给day加多少天
            if( month == 1 || month == 3 || month == 5 || month == 7
                         || month == 8 || month == 10 || month == 0 )   //上面month--后不可能为12,因为最大为12-1=11;
                                                                        //最小为1-1=0,即12月
                day += 31;
            else if( month == 4 || month == 6 || month == 9 || month == 11 )
                day += 30;
            else if( month == 2 )
            {
                if( isLeapYear( year ) )
                    day += 29;
                else
                    day += 28;
            }
        }
        if( month > 12 )
            year++, month %= 12;
        else if( month < 1 )
            year--, month += 12;
        //将相应的星期数字信息转换为字符串
        switch( week )
        {
            case 0 : strcpy(w, "SUN"); break;
            case 1 : strcpy(w, "MON"); break;
            case 2 : strcpy(w, "TUE"); break;
            case 3 : strcpy(w, "WED"); break;
            case 4 : strcpy(w, "THU"); break;
            case 5 : strcpy(w, "FRI"); break;
            case 6 : strcpy(w, "SAT"); break;
        }
        //将相应的月份数字信息转换为字符串
        switch( month )
        {
            case 1 : strcpy(mth, "JAN"); break;
            case 2 : strcpy(mth, "FEB"); break;
            case 3 : strcpy(mth, "MAR"); break;
            case 4 : strcpy(mth, "APR"); break;
            case 5 : strcpy(mth, "MAY"); break;
            case 6 : strcpy(mth, "JUN"); break;
            case 7 : strcpy(mth, "JUL"); break;
            case 8 : strcpy(mth, "AUG"); break;
            case 9 : strcpy(mth, "SEP"); break;
            case 10 : strcpy(mth, "OCT"); break;
            case 11 : strcpy(mth, "NOV"); break;
            case 12 : strcpy(mth, "DEC"); break;
        }
        //根据相应格式进行输出
        cout << w << ", " << setfill('0') << setw(2) << day << ' ' << mth << ' '
            << setfill('0') << setw(4) << year <<' '
            << setfill('0') << setw(2) << hour << ':'
            << setfill('0') << setw(2) << minute << ':'
            << setfill('0') << setw(2) << second << ' '
            << zt <<endl;
        memset( w, '\0', sizeof( w ) );
        memset( mth, '\0', sizeof( mth ) );
        memset( zt, '\0', sizeof( zt ) );
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT研究僧大师兄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值