summaryrefslogtreecommitdiffstats
blob: 79a3d4c57f4f10634452c53048f92b8d10ab4020 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#ifndef DATE_TIME_FILETIME_FUNCTIONS_HPP__
#define DATE_TIME_FILETIME_FUNCTIONS_HPP__

/* Copyright (c) 2004 CrystalClear Software, Inc.
 * Use, modification and distribution is subject to the
 * Boost Software License, Version 1.0. (See accompanying
 * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 * Author: Jeff Garland, Bart Garst
 * $Date: 2009-02-01 06:29:43 -0500 (Sun, 01 Feb 2009) $
 */

/*! @file filetime_functions.hpp
 * Function(s) for converting between a FILETIME structure and a 
 * time object. This file is only available on systems that have
 * BOOST_HAS_FTIME defined.
 */

#include <boost/date_time/compiler_config.hpp>

#if defined(BOOST_HAS_FTIME) // skip this file if no FILETIME

#if defined(BOOST_USE_WINDOWS_H)
#  include <windows.h>
#endif

#include <boost/cstdint.hpp>
#include <boost/date_time/time.hpp>
#include <boost/date_time/date_defs.hpp>

namespace boost {

namespace date_time {

namespace winapi {

#if !defined(BOOST_USE_WINDOWS_H)

    extern "C" {

        struct FILETIME
        {
            boost::uint32_t dwLowDateTime;
            boost::uint32_t dwHighDateTime;
        };
        struct SYSTEMTIME
        {
            boost::uint16_t wYear;
            boost::uint16_t wMonth;
            boost::uint16_t wDayOfWeek;
            boost::uint16_t wDay;
            boost::uint16_t wHour;
            boost::uint16_t wMinute;
            boost::uint16_t wSecond;
            boost::uint16_t wMilliseconds; 
        };

        __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(FILETIME* lpFileTime); 
        __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const FILETIME* lpFileTime, FILETIME* lpLocalFileTime); 
        __declspec(dllimport) void __stdcall GetSystemTime(SYSTEMTIME* lpSystemTime); 
        __declspec(dllimport) int __stdcall SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, FILETIME* lpFileTime); 

    } // extern "C"

#endif // defined(BOOST_USE_WINDOWS_H)

    typedef FILETIME file_time;
    typedef SYSTEMTIME system_time;

    inline void get_system_time_as_file_time(file_time& ft)
    {
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205))
        // Some runtime library implementations expect local times as the norm for ctime.
        file_time ft_utc;
        GetSystemTimeAsFileTime(&ft_utc);
        FileTimeToLocalFileTime(&ft_utc, &ft);
#elif defined(BOOST_NO_GETSYSTEMTIMEASFILETIME)
        system_time st;
        GetSystemTime(&st);
        SystemTimeToFileTime(&st, &ft);
#else
        GetSystemTimeAsFileTime(&ft);
#endif
    }

    /*!
     * The function converts file_time into number of microseconds elapsed since 1970-Jan-01
     *
     * \note Only dates after 1970-Jan-01 are supported. Dates before will be wrapped.
     *
     * \note The function is templated on the FILETIME type, so that
     *       it can be used with both native FILETIME and the ad-hoc
     *       boost::date_time::winapi::file_time type.
     */
    template< typename FileTimeT >
    inline boost::uint64_t file_time_to_microseconds(FileTimeT const& ft)
    {
        /* shift is difference between 1970-Jan-01 & 1601-Jan-01
        * in 100-nanosecond intervals */
        const uint64_t c1 = 27111902UL;
        const uint64_t c2 = 3577643008UL; // issues warning without 'UL'
        const uint64_t shift = (c1 << 32) + c2;

        union {
            FileTimeT as_file_time;
            uint64_t as_integer; // 100-nanos since 1601-Jan-01
        } caster;
        caster.as_file_time = ft;

        caster.as_integer -= shift; // filetime is now 100-nanos since 1970-Jan-01
        return (caster.as_integer / 10); // truncate to microseconds
    }

} // namespace winapi

//! Create a time object from an initialized FILETIME struct.
/*!
 * Create a time object from an initialized FILETIME struct.
 * A FILETIME struct holds 100-nanosecond units (0.0000001). When 
 * built with microsecond resolution the file_time's sub second value 
 * will be truncated. Nanosecond resolution has no truncation.
 *
 * \note The function is templated on the FILETIME type, so that
 *       it can be used with both native FILETIME and the ad-hoc
 *       boost::date_time::winapi::file_time type.
 */
template< typename TimeT, typename FileTimeT >
inline
TimeT time_from_ftime(const FileTimeT& ft)
{
    typedef typename TimeT::date_type date_type;
    typedef typename TimeT::date_duration_type date_duration_type;
    typedef typename TimeT::time_duration_type time_duration_type;

    // https://svn.boost.org/trac/boost/ticket/2523
    // Since this function can be called with arbitrary times, including ones that
    // are before 1970-Jan-01, we'll have to cast the time a bit differently,
    // than it is done in the file_time_to_microseconds function. This allows to
    // avoid integer wrapping for dates before 1970-Jan-01.
    union {
        FileTimeT as_file_time;
        uint64_t as_integer; // 100-nanos since 1601-Jan-01
    } caster;
    caster.as_file_time = ft;

    uint64_t sec = caster.as_integer / 10000000UL;
    uint32_t sub_sec = (caster.as_integer % 10000000UL) // 100-nanoseconds since the last second
#if !defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
        / 10; // microseconds since the last second
#else
        * 100; // nanoseconds since the last second
#endif

    // split sec into usable chunks: days, hours, minutes, & seconds
    const uint32_t sec_per_day = 86400; // seconds per day
    uint32_t days = static_cast< uint32_t >(sec / sec_per_day);
    uint32_t tmp = static_cast< uint32_t >(sec % sec_per_day);
    uint32_t hours = tmp / 3600; // sec_per_hour
    tmp %= 3600;
    uint32_t minutes = tmp / 60; // sec_per_min
    tmp %= 60;
    uint32_t seconds = tmp; // seconds

    date_duration_type dd(days);
    date_type d = date_type(1601, Jan, 01) + dd;
    return TimeT(d, time_duration_type(hours, minutes, seconds, sub_sec));
}

}} // boost::date_time

#endif // BOOST_HAS_FTIME

#endif // DATE_TIME_FILETIME_FUNCTIONS_HPP__