This file is indexed.

/usr/lib/python3/dist-packages/xlrd/xldate.py is in python3-xlrd 1.1.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# -*- coding: cp1252 -*-
# Copyright (c) 2005-2008 Stephen John Machin, Lingfo Pty Ltd
# This module is part of the xlrd package, which is released under a
# BSD-style licence.
# No part of the content of this file was derived from the works of David Giffin.
"""
Tools for working with dates and times in Excel files.

The conversion from ``days`` to ``(year, month, day)`` starts with
an integral "julian day number" aka JDN.
FWIW:

- JDN 0 corresponds to noon on Monday November 24 in Gregorian year -4713.

More importantly:

- Noon on Gregorian 1900-03-01 (day 61 in the 1900-based system) is JDN 2415080.0
- Noon on Gregorian 1904-01-02 (day  1 in the 1904-based system) is JDN 2416482.0

"""
import datetime

_JDN_delta = (2415080 - 61, 2416482 - 1)
assert _JDN_delta[1] - _JDN_delta[0] == 1462

# Pre-calculate the datetime epochs for efficiency.
epoch_1904 = datetime.datetime(1904, 1, 1)
epoch_1900 = datetime.datetime(1899, 12, 31)
epoch_1900_minus_1 = datetime.datetime(1899, 12, 30)

# This is equivalent to 10000-01-01:
_XLDAYS_TOO_LARGE = (2958466, 2958466 - 1462)


class XLDateError(ValueError):
    "A base class for all datetime-related errors."


class XLDateNegative(XLDateError):
    "``xldate < 0.00``"


class XLDateAmbiguous(XLDateError):
    "The 1900 leap-year problem ``(datemode == 0 and 1.0 <= xldate < 61.0)``"


class XLDateTooLarge(XLDateError):
    "Gregorian year 10000 or later"


class XLDateBadDatemode(XLDateError):
    "``datemode`` arg is neither 0 nor 1"


class XLDateBadTuple(XLDateError):
    pass


def xldate_as_tuple(xldate, datemode):
    """
    Convert an Excel number (presumed to represent a date, a datetime or a time) into
    a tuple suitable for feeding to datetime or mx.DateTime constructors.

    :param xldate: The Excel number
    :param datemode: 0: 1900-based, 1: 1904-based.
    :raises xlrd.xldate.XLDateNegative:
    :raises xlrd.xldate.XLDateAmbiguous:

    :raises xlrd.xldate.XLDateTooLarge:
    :raises xlrd.xldate.XLDateBadDatemode:
    :raises xlrd.xldate.XLDateError:
    :returns: Gregorian ``(year, month, day, hour, minute, nearest_second)``.

    .. warning::

      When using this function to interpret the contents of a workbook, you
      should pass in the :attr:`~xlrd.book.Book.datemode`
      attribute of that workbook. Whether the workbook has ever been anywhere
      near a Macintosh is irrelevant.

    .. admonition:: Special case

        If ``0.0 <= xldate < 1.0``, it is assumed to represent a time;
        ``(0, 0, 0, hour, minute, second)`` will be returned.

    .. note::

        ``1904-01-01`` is not regarded as a valid date in the ``datemode==1``
        system; its "serial number" is zero.
    """
    if datemode not in (0, 1):
        raise XLDateBadDatemode(datemode)
    if xldate == 0.00:
        return (0, 0, 0, 0, 0, 0)
    if xldate < 0.00:
        raise XLDateNegative(xldate)
    xldays = int(xldate)
    frac = xldate - xldays
    seconds = int(round(frac * 86400.0))
    assert 0 <= seconds <= 86400
    if seconds == 86400:
        hour = minute = second = 0
        xldays += 1
    else:
        # second = seconds % 60; minutes = seconds // 60
        minutes, second = divmod(seconds, 60)
        # minute = minutes % 60; hour    = minutes // 60
        hour, minute = divmod(minutes, 60)
    if xldays >= _XLDAYS_TOO_LARGE[datemode]:
        raise XLDateTooLarge(xldate)

    if xldays == 0:
        return (0, 0, 0, hour, minute, second)

    if xldays < 61 and datemode == 0:
        raise XLDateAmbiguous(xldate)

    jdn = xldays + _JDN_delta[datemode]
    yreg = ((((jdn * 4 + 274277) // 146097) * 3 // 4) + jdn + 1363) * 4 + 3
    mp = ((yreg % 1461) // 4) * 535 + 333
    d = ((mp % 16384) // 535) + 1
    # mp /= 16384
    mp >>= 14
    if mp >= 10:
        return ((yreg // 1461) - 4715, mp - 9, d, hour, minute, second)
    else:
        return ((yreg // 1461) - 4716, mp + 3, d, hour, minute, second)


def xldate_as_datetime(xldate, datemode):
    """
    Convert an Excel date/time number into a :class:`datetime.datetime` object.

    :param xldate: The Excel number
    :param datemode: 0: 1900-based, 1: 1904-based.

    :returns: A :class:`datetime.datetime` object.
    """

    # Set the epoch based on the 1900/1904 datemode.
    if datemode:
        epoch = epoch_1904
    else:
        if xldate < 60:
            epoch = epoch_1900
        else:
            # Workaround Excel 1900 leap year bug by adjusting the epoch.
            epoch = epoch_1900_minus_1

    # The integer part of the Excel date stores the number of days since
    # the epoch and the fractional part stores the percentage of the day.
    days = int(xldate)
    fraction = xldate - days

    # Get the the integer and decimal seconds in Excel's millisecond resolution.
    seconds = int(round(fraction * 86400000.0))
    seconds, milliseconds = divmod(seconds, 1000)

    return epoch + datetime.timedelta(days, seconds, 0, milliseconds)


# === conversions from date/time to xl numbers

def _leap(y):
    if y % 4: return 0
    if y % 100: return 1
    if y % 400: return 0
    return 1

_days_in_month = (None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)


def xldate_from_date_tuple(date_tuple, datemode):
    """
    Convert a date tuple (year, month, day) to an Excel date.

    :param year: Gregorian year.
    :param month: ``1 <= month <= 12``
    :param day: ``1 <= day <= last day of that (year, month)``
    :param datemode: 0: 1900-based, 1: 1904-based.
    :raises xlrd.xldate.XLDateAmbiguous:
    :raises xlrd.xldate.XLDateBadDatemode:
    :raises xlrd.xldate.XLDateBadTuple:
      ``(year, month, day)`` is too early/late or has invalid component(s)
    :raises xlrd.xldate.XLDateError:
    """
    year, month, day = date_tuple

    if datemode not in (0, 1):
        raise XLDateBadDatemode(datemode)

    if year == 0 and month == 0 and day == 0:
        return 0.00

    if not (1900 <= year <= 9999):
        raise XLDateBadTuple("Invalid year: %r" % ((year, month, day),))
    if not (1 <= month <= 12):
        raise XLDateBadTuple("Invalid month: %r" % ((year, month, day),))
    if  day < 1 \
    or (day > _days_in_month[month] and not(day == 29 and month == 2 and _leap(year))):
        raise XLDateBadTuple("Invalid day: %r" % ((year, month, day),))

    Yp = year + 4716
    M = month
    if M <= 2:
        Yp = Yp - 1
        Mp = M + 9
    else:
        Mp = M - 3
    jdn = (1461 * Yp // 4) + ((979 * Mp + 16) // 32) + \
        day - 1364 - (((Yp + 184) // 100) * 3 // 4)
    xldays = jdn - _JDN_delta[datemode]
    if xldays <= 0:
        raise XLDateBadTuple("Invalid (year, month, day): %r" % ((year, month, day),))
    if xldays < 61 and datemode == 0:
        raise XLDateAmbiguous("Before 1900-03-01: %r" % ((year, month, day),))
    return float(xldays)


def xldate_from_time_tuple(time_tuple):
    """
    Convert a time tuple ``(hour, minute, second)`` to an Excel "date" value
    (fraction of a day).

    :param hour: ``0 <= hour < 24``
    :param minute: ``0 <= minute < 60``
    :param second: ``0 <= second < 60``
    :raises xlrd.xldate.XLDateBadTuple: Out-of-range hour, minute, or second
    """
    hour, minute, second = time_tuple
    if 0 <= hour < 24 and 0 <= minute < 60 and 0 <= second < 60:
        return ((second / 60.0 + minute) / 60.0 + hour) / 24.0
    raise XLDateBadTuple("Invalid (hour, minute, second): %r" % ((hour, minute, second),))


def xldate_from_datetime_tuple(datetime_tuple, datemode):
    """
    Convert a datetime tuple ``(year, month, day, hour, minute, second)`` to an
    Excel date value.
    For more details, refer to other xldate_from_*_tuple functions.

    :param datetime_tuple: ``(year, month, day, hour, minute, second)``
    :param datemode: 0: 1900-based, 1: 1904-based.
    """
    return (
        xldate_from_date_tuple(datetime_tuple[:3], datemode)
        +
        xldate_from_time_tuple(datetime_tuple[3:])
        )