• muduo 库解析之四:TimeZone


    源码

    TimeZone.h

    #pragma once
    #include <time.h>
    #include <memory>
    
    #include "Copyable.h"
    
    namespace muduo
    {
        class TimeZone : public Copyable
        {
        public:
            TimeZone() = default;
            explicit TimeZone(const char *zone_file);
            TimeZone(int east_of_utc, const char *tzname);
    
            bool valid() const
            {
                return static_cast<bool>(data_);
            }
    
            struct tm to_local_time(time_t seconds_since_epoch) const;
            time_t from_local_time(const struct tm &) const;
    
            static struct tm to_utc_time(time_t seconds_since_epoch, bool yday = false);
            static time_t from_utc_time(const struct tm &);
            static time_t from_utc_time(int year, int month, int day, int hour, int minute, int seconds);
    
            struct Data;
    
        private:
            std::shared_ptr<Data> data_;
        };
    }
    

    TimeZone.cc

    #include "TimeZone.h"
    
    #include <vector>
    #include <string>
    #include <stdexcept>
    #include <algorithm>
    #include <stdio.h>
    #include <endian.h>
    #include <assert.h>
    
    #include "NonCopyable.h"
    #include "Types.h"
    #include "Date.h"
    
    namespace muduo
    {
        namespace detail
        {
            struct Transition
            {
                time_t gmt_time;
                time_t local_time;
                int local_time_index;
    
                Transition(time_t t, time_t l, int local_index) : gmt_time(t), local_time(l), local_time_index(local_index)
                {
                }
            };
    
            struct Comp
            {
                bool compare_gmt;
    
                Comp(bool gmt) : compare_gmt(gmt)
                {
                }
    
                bool operator()(const Transition &lhs, const Transition &rhs) const
                {
                    if (compare_gmt)
                        return lhs.gmt_time < rhs.gmt_time;
                    else
                        return lhs.local_time < rhs.local_time;
                }
    
                bool equal(const Transition &lhs, const Transition &rhs) const
                {
                    if (compare_gmt)
                        return lhs.gmt_time == rhs.gmt_time;
                    else
                        return lhs.local_time == rhs.local_time;
                }
            };
    
            struct LocalTime
            {
                time_t gmt_offset;
                bool is_dst;
                int arrb_index;
    
                LocalTime(time_t offset, bool dst, int arrb) : gmt_offset(offset), is_dst(dst), arrb_index(arrb)
                {
                }
            };
    
            inline void fill_hms(unsigned seconds, struct tm *utc)
            {
                utc->tm_sec = seconds % 60;
                unsigned minutes = seconds / 60;
                utc->tm_min = minutes;
                utc->tm_hour = minutes / 60;
            }
        }
    
        const int kSecondsPerDay = 24 * 60 * 60;
    
        struct TimeZone::Data
        {
            std::vector<detail::Transition> transitions;
            std::vector<detail::LocalTime> local_times;
            std::vector<std::string> names;
            std::string abbreviation;
        };
    
        namespace detail
        {
            class File : public NonCopyable
            {
            public:
                File(const char *file) : fp_(::fopen(file, "rb"))
                {
                }
    
                ~File()
                {
                    if (fp_)
                    {
                        ::fclose(fp_);
                    }
                }
    
                bool valid() const { return fp_; }
    
                std::string read_bytes(int n)
                {
                    char buf[n];
                    ssize_t nr = ::fread(buf, 1, n, fp_);
                    if (nr != n)
                        throw std::logic_error("no enough data");
                    return std::string(buf, n);
                }
    
                int32_t read_int32()
                {
                    int32_t x = 0;
                    ssize_t nr = ::fread(&x, 1, sizeof(int32_t), fp_);
                    if (nr != sizeof(int32_t))
                        throw std::logic_error("bad int32_t data");
                    return be32toh(x); //@ convert byte order
                }
    
                uint8_t read_uint8()
                {
                    uint8_t x = 0;
                    ssize_t nr = ::fread(&x, 1, sizeof(uint8_t), fp_);
                    if (nr != sizeof(uint8_t))
                        throw std::logic_error("bad uint8_t data");
                    return x;
                }
    
            private:
                FILE *fp_;
            };
    
            bool read_time_zone_file(const char *zone_file, struct TimeZone::Data *data)
            {
                File f(zone_file);
                if (f.valid())
                {
                    try
                    {
                        std::string header = f.read_bytes(4);
                        if (header != "TZif")
                            throw std::logic_error("bad header");
                        std::string version = f.read_bytes(1);
                        f.read_bytes(15);
    
                        int32_t is_gmt_cnt = f.read_int32();
                        int32_t is_std_cnt = f.read_int32();
                        int32_t leap_cnt = f.read_int32();
                        int32_t time_cnt = f.read_int32();
                        int32_t type_cnt = f.read_int32();
                        int32_t char_cnt = f.read_int32();
    
                        std::vector<int32_t> trans;
                        std::vector<int> local_times;
                        trans.reserve(time_cnt);
                        for (int i = 0; i < time_cnt; ++i)
                        {
                            trans.push_back(f.read_int32());
                        }
    
                        for (int i = 0; i < time_cnt; ++i)
                        {
                            uint8_t local = f.read_uint8();
                            local_times.push_back(local);
                        }
    
                        for (int i = 0; i < type_cnt; ++i)
                        {
                            int32_t gmt_off = f.read_int32();
                            uint8_t is_dst = f.read_uint8();
                            uint8_t abbrind = f.read_uint8();
                            data->local_times.push_back(LocalTime(gmt_off, is_dst, abbrind));
                        }
    
                        for (int i = 0; i < time_cnt; ++i)
                        {
                            int local_idx = local_times[i];
                            time_t localtime = trans[i] + data->local_times[local_idx].gmt_offset;
                            data->transitions.push_back(Transition(trans[i], localtime, local_idx));
                        }
    
                        data->abbreviation = f.read_bytes(char_cnt);
    
                        for (int i = 0; i < leap_cnt; ++i)
                        {
                            // int32_t leaptime = f.read_int32();
                            // int32_t cumleap = f.read_int32();
                        }
    
                        (void)is_std_cnt;
                        (void)is_gmt_cnt;
                    }
                    catch (const std::logic_error &e)
                    {
                        fprintf(stderr, "%s
    ", e.what());
                    }
                }
                return true;
            }
    
            const LocalTime *find_local_time(const TimeZone::Data &data, Transition sentry, Comp comp)
            {
                const LocalTime *local = NULL;
    
                if (data.transitions.empty() || comp(sentry, data.transitions.front()))
                {
                    local = &data.local_times.front();
                }
                else
                {
                    std::vector<Transition>::const_iterator trans_i = std::lower_bound(data.transitions.begin(), data.transitions.end(), sentry, comp);
                    if (trans_i != data.transitions.end())
                    {
                        if (!comp.equal(sentry, *trans_i))
                        {
                            assert(trans_i != data.transitions.begin());
                            --trans_i;
                        }
    
                        local = &data.local_times[trans_i->local_time_index];
                    }
                    else
                    {
                        local = &data.local_times[data.transitions.back().local_time_index];
                    }
                }
                return local;
            }
    
        } //@ namespace detail
    
        TimeZone::TimeZone(const char *zone_file) : data_(new TimeZone::Data)
        {
            if (!detail::read_time_zone_file(zone_file, data_.get()))
                data_.reset();
        }
    
        TimeZone::TimeZone(int east_of_utc, const char *tzname) : data_(new TimeZone::Data)
        {
            data_->local_times.push_back(detail::LocalTime(east_of_utc, false, 0));
            data_->abbreviation = tzname;
        }
    
        struct tm TimeZone::to_local_time(time_t seconds) const
        {
            struct tm local_time;
            mem_zero(&local_time, sizeof(local_time));
            assert(data_ != NULL);
            const Data &data(*data_);
    
            detail::Transition sentry(seconds, 0, 0);
            const detail::LocalTime *local = find_local_time(data, sentry, detail::Comp(true));
            if (local)
            {
                time_t local_seconds = seconds + local->gmt_offset;
                ::gmtime_r(&local_seconds, &local_time);
                local_time.tm_isdst = local->is_dst;
                local_time.tm_gmtoff = local->gmt_offset;
                local_time.tm_zone = &data.abbreviation[local->arrb_index];
            }
            return local_time;
        }
    
        time_t TimeZone::from_local_time(const struct tm &local) const
        {
            assert(data_ != NULL);
            const Data &data(*data_);
            struct tm tmp = local;
            time_t seconds = ::timegm(&tmp);
            detail::Transition sentry(0, seconds, 0);
            const detail::LocalTime *local_time = find_local_time(data, sentry, detail::Comp(false));
            if (local.tm_isdst)
            {
                struct tm try_tm = to_local_time(seconds - local_time->gmt_offset);
                if (!try_tm.tm_isdst && try_tm.tm_hour == local.tm_hour && try_tm.tm_min == local.tm_min)
                {
                    seconds -= 3600;
                }
            }
            return seconds - local_time->gmt_offset;
        }
    
        struct tm TimeZone::to_utc_time(time_t seconds_since_epoch, bool yday)
        {
            struct tm utc;
            mem_zero(&utc, sizeof(utc));
            utc.tm_zone = "GMT";
            int seconds = static_cast<int>(seconds_since_epoch % kSecondsPerDay);
            int days = static_cast<int>(seconds_since_epoch / kSecondsPerDay);
            if (seconds < 0)
            {
                seconds += kSecondsPerDay;
                --days;
            }
            detail::fill_hms(seconds, &utc);
            Date date(days + Date::kJulianDayOf1970_01_01);
            Date::YearMonthDay ymd = date.year_month_day();
            utc.tm_year = ymd.year - 1900;
            utc.tm_mon = ymd.month - 1;
            utc.tm_mday = ymd.day;
            utc.tm_wday = date.week_day();
    
            if (yday)
            {
                Date start_of_year(ymd.year, 1, 1);
                utc.tm_yday = date.julian_day_number() - start_of_year.julian_day_number();
            }
            return utc;
        }
    
        time_t TimeZone::from_utc_time(const struct tm &utc)
        {
            return from_utc_time(utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_mon, utc.tm_sec);
        }
    
        time_t TimeZone::from_utc_time(int year, int month, int day, int hour, int minute, int seconds)
        {
            Date date(year, month, day);
            int seconds_in_day = hour * 3600 + minute * 60 + seconds;
            time_t days = date.julian_day_number() - Date::kJulianDayOf1970_01_01;
            return days * kSecondsPerDay + seconds_in_day;
        }
    }
    
  • 相关阅读:
    变分自编码器(Variational Autoencoder, VAE)通俗教程
    神经网络图灵机(Neural Turing Machines, NTM)
    【Java设计模式】单例模式
    SupportV7包中 SwipeRefreshLayout 修改下拉控件的距离
    eclipse项目导入androidstudio
    LiveWriter Test
    【Android学习】XML文本的三种解析方式(通过搭建本地的Web项目提供XML文件)
    【百度地图学习-一】初始化以及TextOverlay
    【Android学习】四种布局方式
    【Android学习】数据传递三种方式
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/14698251.html
Copyright © 2020-2023  润新知