blob: 68c8669258b802a9b2d1b4b3e440dd781f97d6d3 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import datetime
import six
from decimal import Decimal, getcontext
from pytz import utc
def _epoch():
"""
Return the unix epoch in datetime.datetime form for the
timezone provided.
Returns
-------
epoch : datetime.datetime
"""
return datetime.datetime.fromtimestamp(0, utc)
def indent(text, spaces):
block = ' ' * spaces
return '\n'.join(block + x for x in text.split('\n'))
def to_unixtime_micros(timestamp, format = "%Y-%m-%dT%H:%M:%S.%f"):
"""
Convert incoming datetime value to a integer representing
the number of microseconds since the unix epoch
Parameters
---------
timestamp : datetime.datetime or string
If a string is provided, a format must be provided as well.
A tuple may be provided in place of the timestamp with a
string value and a format. This is useful for predicates
and setting values where this method is indirectly called.
Timezones provided in the string are not supported at this
time. UTC unless provided in a datetime object.
format : Required if a string timestamp is provided
Uses the C strftime() function, see strftime(3) documentation.
Returns
-------
int : Microseconds since unix epoch
"""
# Validate input
if isinstance(timestamp, datetime.datetime):
pass
elif isinstance(timestamp, six.string_types):
timestamp = datetime.datetime.strptime(timestamp, format)
elif isinstance(timestamp, tuple):
timestamp = datetime.datetime.strptime(timestamp[0], timestamp[1])
else:
raise ValueError("Invalid timestamp type. " +
"You must provide a datetime.datetime or a string.")
# If datetime has a valid timezone assigned, convert it to UTC.
if timestamp.tzinfo and timestamp.utcoffset():
timestamp = timestamp.astimezone(utc)
# If datetime has no timezone, it is assumed to be UTC
else:
timestamp = timestamp.replace(tzinfo=utc)
# Return the unixtime_micros for the provided datetime and locale.
# Avoid timedelta.total_seconds() for py2.6 compatibility.
td = timestamp - _epoch()
td_micros = td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6
return int(td_micros)
def from_unixtime_micros(unixtime_micros):
"""
Convert the input unixtime_micros value to a datetime in UTC.
Parameters
----------
unixtime_micros : int
Number of microseconds since the unix epoch.
Returns
-------
timestamp : datetime.datetime in UTC
"""
if isinstance(unixtime_micros, int):
return _epoch() + datetime.timedelta(microseconds=unixtime_micros)
else:
raise ValueError("Invalid unixtime_micros value." +
"You must provide an integer value.")
def from_hybridtime(hybridtime):
"""
Convert a raw HybridTime value to a datetime in UTC.
Parameters
----------
hybridtime : long
Returns
-------
timestamp : datetime.datetime in UTC
"""
# Add 1 so the value is usable for snapshot scans
return from_unixtime_micros(int(hybridtime >> 12) + 1)
def to_unscaled_decimal(decimal, context=None):
"""
Convert incoming decimal value to a int representing
the unscaled decimal value.
Parameters
---------
decimal : Decimal
The decimal value to convert to an unscaled int
context : Context
The optional context to use
Returns
-------
int : The unscaled decimal int
"""
if context is None:
context = getcontext()
scale = get_decimal_scale(decimal)
return decimal.scaleb(scale, context).to_integral_exact(None, context)
def from_unscaled_decimal(unscaled_decimal, scale, context=None):
"""
Convert the input unscaled_decimal value to a Decimal instance.
Parameters
----------
unscaled_decimal : int
The unscaled int value of a decimal
scale : int
The scale that should be used when converting
context : Context
The optional context to use
Returns
-------
decimal : The scaled Decimal
"""
if context is None:
context = getcontext()
return Decimal(unscaled_decimal, context).scaleb(-scale, context)
def get_decimal_scale(decimal):
"""
Get the scale of the decimal.
Parameters
---------
decimal : Decimal
The decimal value
Returns
-------
int : The calculated scale
"""
return max(0, -decimal.as_tuple().exponent)
def unix_epoch_days_to_date(ndays):
"""
Convert number of days since the unix epoch into datetime.date in UTC timezone.
Number of days converted into timestamp by multiplying days on number
of seconds per day (86400).
Parameters
---------
ndays : integer
The number of days since the unix epoch
Returns
-------
datetime.date : calendar date for "ndays" days since unix epoch
"""
return datetime.datetime.utcfromtimestamp(ndays * 86400).date()
def date_to_unix_epoch_days(date):
"""
Convert datetime.date value to a integer representing
the number of days since the unix epoch.
Parameters
---------
date : datetime.date
Returns
-------
int : Number of days since unix epoch
"""
delta = date - datetime.datetime.utcfromtimestamp(0).date()
return delta.days