Python数字日期和时间

Posted HT . WANG

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python数字日期和时间相关的知识,希望对你有一定的参考价值。

1.数字的四舍五入

对浮点数执行指定精度的舍入运算

类似与输出格式控制,但不同与输出格式控制,输出格式控制仅控制输出精度不会做近似处理

使用内置的 round(value, ndigits) 函数, 当一个值刚好在两个边界的中间的时候,round 函数返回离它最近的偶数。 也就是说,对1.5或者2.5的舍入运算都会得到2

#format格式控制

>>> x = 1.23456
>>> format(x, '0.2f')
'1.23'
>>> format(x, '0.3f')
'1.235'
>>> 'value is :0.3f'.format(x)
'value is 1.235'
>>>

#round函数四舍 五取最近偶 处理
>>> round(1.23, 1)
1.2
>>> round(1.27, 1)
1.3
>>> round(-1.27, 1)
-1.3
>>> round(1.25361,3)
1.254
>>> round(1.5)
2
>>> round(2.5)
2

传给 round() 函数的 ndigits 参数可以是负数,这种情况下, 舍入运算会作用在十位、百位、千位等上面。

>>> a = 1627731
>>> round(a, -1)
1627730
>>> round(a, -2)
1627700
>>> round(a, -3)
1628000
>>>

应用于浮点数运算结构比较来标准化比较精度范围

>>> a = 2.1
>>> b = 4.2
>>> c = a + b
>>> c
6.300000000000001  #所有浮点数规范遵从IEEEE754二进制浮点数算术标准(ANSI/IEEE Std 754-1985)的编程语言
>>> print(c==6.3)
False
>>> c = round(c, 2) # "Fix" result (???)
>>> c
6.3
>>> print(c==6.3)
True

2.执行精确的浮点数运算

如上一节所示,浮点数的一个普遍问题是它们并不能精确的表示十进制数。 并且,即使是最简单的数学运算也会产生小的误差,

这些错误是由底层CPU和IEEE 754标准通过自己的浮点单位去执行算术时的特征。 由于Python的浮点数据类型使用底层表示存储数据

如果想更加精确(并能容忍一定的性能损耗),你可以使用 decimal 模块:

>>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a + b
Decimal('6.3')
>>> print(a + b)
6.3
>>> (a + b) == Decimal('6.3')
True

decimal对数字位数的控制,创建本地会话更改设置ctx.prec

>>> from decimal import localcontext
>>> a = Decimal('1.3')
>>> b = Decimal('1.7')
>>> print(a / b)
0.7647058823529411764705882353
>>> with localcontext() as ctx:
...     ctx.prec = 3
...     print(a / b)
...
0.765
>>> with localcontext() as ctx:
...     ctx.prec = 50
...     print(a / b)
...
0.76470588235294117647058823529411764705882352941176
>>>

3.数字的格式化输出

% 和 format

>>> x = 1234.56789
'''
%
'''
>>> '%0.2f' % x
'1234.57'
>>> '%10.1f' % x
'    1234.6'
>>> '%-10.1f' % x
'1234.6    '
>>>

'''
format
'''

>>> # 保留2位小数
>>> format(x, '0.2f')
'1234.57'

>>> #右对齐且宽度为10 保留2位小数
>>> format(x, '>10.1f')
'    1234.6'

>>> #左对齐且宽度为10 保留1位小数
>>> format(x, '<10.1f')
'1234.6    '

>>> # 居中且宽度为10 保留1位小数
>>> format(x, '^10.1f')
'  1234.6  '

>>> # 逗号显示千位符
>>> format(x, ',')
'1,234.56789'

'''
指定宽度和精度的一般形式是 '[<>^]?width[,]?(.digits)?' 
'''
#无对齐  宽度为0 逗号显示千位符 保留1位小数
>>> format(x, '0,.1f')
'1,234.6'
>>>

4.二 八 十六进制整数

为了将整数转换为二进制、八进制或十六进制的文本串, 可以分用 bin() , oct() 或 hex() 函数:

>>> x = 1234
>>> bin(x) #二进制
'0b10011010010'
>>> oct(x) #八进制
'0o2322'
>>> hex(x) #十六进制
'0x4d2'
>>>

如果不想输出 0b , 0o 或者 0x 的前缀的话,可以使用 format() 函数

>>> x = 1234
>>> format(x, 'b')
'10011010010'
>>> format(x, 'o')
'2322'
>>> format(x, 'x')
'4d2'

>>> x = -1234
>>> format(x, 'b')
'-10011010010'
>>> format(x, 'x')
'-4d2'
>>>

 Python指定八进制数的语法跟其他语言稍有不同。需确保八进制数的前缀是 0o

>>> import os
>>> os.chmod('script.py', o0755)

5.字节到大整数的打包与解包

有一个字节字符串并想将它解压成一个整数。或者将一个大整数转换为一个字节字符串。

(1)为了将字节字符解析为整数,使用 int.from_bytes() 方法

data = b'\\x00\\x124V\\x00x\\x90\\xab\\x00\\xcd\\xef\\x01\\x00#\\x004'

>>> len(data)
16
>>> int.from_bytes(data, 'little') #little表示正序
69120565665751139577663547927094891008
>>> int.from_bytes(data, 'big') #big表示反序
94522842520747284487117727783387188
>>>

(2)为了将一个大整数转换为一个字节字符串,使用 int.to_bytes() 方法

>>> x = 94522842520747284487117727783387188
>>> x.to_bytes(16, 'big')
b'\\x00\\x124V\\x00x\\x90\\xab\\x00\\xcd\\xef\\x01\\x00#\\x004'
>>> x.to_bytes(16, 'little')
b'4\\x00#\\x00\\x01\\xef\\xcd\\x00\\xab\\x90x\\x00V4\\x12\\x00'
>>>

字节顺序规则(little或big)仅仅指定了构建整数时的字节的低位高位排列方式

>>> x = 0x01020304
>>> x.to_bytes(4, 'big')
b'\\x01\\x02\\x03\\x04'
>>> x.to_bytes(4, 'little')
b'\\x04\\x03\\x02\\x01'
>>>

6.复数的数学运算

复数可以用使用函数 complex(real, imag) 或者是带有后缀j的浮点数来指定。

'''
复数表示
'''
>>> a = complex(2, 4)
>>> b = 3 - 5j
>>> a
(2+4j)
>>> b
(3-5j)
>>>
'''
复数实部虚部获取
'''
>>> a.real
2.0
>>> a.imag
4.0
>>> a.conjugate()
(2-4j)
>>>
'''
复数简单数学运算
'''
>>> a + b
(5-1j)
>>> a * b
(26+2j)
>>> a / b
(-0.4117647058823529+0.6470588235294118j)
>>> abs(a)
4.47213595499958
>>>
'''
复数复杂数学运算借助cmath模块
'''
>>> import cmath
>>> cmath.sin(a)
(24.83130584894638-11.356612711218174j)
>>> cmath.cos(a)
(-11.36423470640106-24.814651485634187j)
>>> cmath.exp(a)
(-4.829809383269385-5.5920560936409816j)

Python的标准数学函数确实情况下并不能产生复数值,因此代码中不可能会出现复数返回值

如果你想生成一个复数返回结果,你必须显示的使用 cmath 模块

>>> import math
>>> math.sqrt(-1)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
ValueError: math domain error
>>>

>>> import cmath
>>> cmath.sqrt(-1)
1j
>>>

7.无穷大与NaN

使用 float() 来创建

>>> a = float('inf')
>>> b = float('-inf')
>>> c = float('nan')
>>> a
inf
>>> b
-inf
>>> c
nan
>>>

>>> math.isinf(a)
True
>>> math.isnan(c)
True
>>>

注意:

(1)无穷大数在执行数学计算的时候会传播

>>> a = float('inf')
>>> a + 45
inf
>>> a * 10
inf
>>> 10 / a
0.0
>>>

(2)Nan特殊性

'''
有些操作时未定义的并会返回一个NaN结果
'''
>>> a = float('inf')
>>> a/a
nan
>>> b = float('-inf')
>>> a + b
nan
>>>

'''
NaN值会在所有操作中传播,而不会产生异常
'''
>>> c = float('nan')
>>> c + 23
nan
>>> c / 2
nan
>>> c * 2
nan
>>> math.sqrt(c)
nan
>>>

'''
NaN值的一个特别的地方时它们之间的比较操作总是返回False
'''
>>> c = float('nan')
>>> d = float('nan')
>>> c == d
False
>>> c is d
False
>>>

8.分数运算

fractions 模块可以被用来执行包含分数的数学运算

>>> from fractions import Fraction
>>> a = Fraction(5, 4)
>>> b = Fraction(7, 16)
>>> print(a + b)
27/16
>>> print(a * b)
35/64

>>> # Getting numerator/denominator
>>> c = a * b
>>> c.numerator
35
>>> c.denominator
64

>>> # Converting to a float
>>> float(c)
0.546875

>>>#定义:通过限制分母的大小来取一个近似值提高精度。格式:fractionobject.limit_denominator('分母最大值')
>>> print(c.limit_denominator(8))
4/7

>>> # 浮点数转化为分数
>>> x = 3.75
>>> y = Fraction(*x.as_integer_ratio())
>>> y
Fraction(15, 4)
>>>

9.大型数组运算

涉及到数组的重量级运算操作,可以使用 NumPy 库

>>> # Python lists
>>> x = [1, 2, 3, 4]
>>> y = [5, 6, 7, 8]
>>> x * 2
[1, 2, 3, 4, 1, 2, 3, 4]
>>> x + 10
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> x + y
[1, 2, 3, 4, 5, 6, 7, 8]

>>> # Numpy arrays
>>> import numpy as np
>>> ax = np.array([1, 2, 3, 4])
>>> ay = np.array([5, 6, 7, 8])
>>> ax * 2
array([2, 4, 6, 8])
>>> ax + 10
array([11, 12, 13, 14])
>>> ax + ay
array([ 6, 8, 10, 12])
>>> ax * ay
array([ 5, 12, 21, 32])
>>>

注意:NumPy 中的标量运算(比如 ax * 2 或 ax + 10 )会作用在每一个元素上。 另外,当两个操作数都是数组的时候执行元素对等位置计算,并最终生成一个新的数组。

NumPy 还为数组操作提供了大量的通用函数,这些函数可以作为 math 模块中类似函数的替代。

>>> np.sqrt(ax)
array([ 1. , 1.41421356, 1.73205081, 2. ])
>>> np.cos(ax)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])
>>>

多维数组作用在每一个元素上,其索引功能类似多维列表索引功能

>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])

>>> # Select row 1
>>> a[1]
array([5, 6, 7, 8])

>>> # Select column 1
>>> a[:,1]
array([ 2, 6, 10])

>>> # Select a subregion and change it
>>> a[1:3, 1:3]
array([[ 6, 7],
        [10, 11]])
>>> a[1:3, 1:3] += 10
>>> a
array([[ 1, 2, 3, 4],
        [ 5, 16, 17, 8],
        [ 9, 20, 21, 12]])

>>> # Broadcast a row vector across an operation on all rows
>>> a + [100, 101, 102, 103]
array([[101, 103, 105, 107],
        [105, 117, 119, 111],
        [109, 121, 123, 115]])
>>> a
array([[ 1, 2, 3, 4],
        [ 5, 16, 17, 8],
        [ 9, 20, 21, 12]])

>>> # Conditional assignment on an array
>>> np.where(a < 10, a, 10)
array([[ 1, 2, 3, 4],
        [ 5, 10, 10, 8],
        [ 9, 10, 10, 10]])
>>>

10.矩阵与线性代数运算

借助numpy库构造矩阵对象,完成矩阵和线性代数运算(矩阵乘法、寻找行列式、求解线性方程组)

>>> import numpy as np
>>> m = np.matrix([[1,-2,3],[0,4,5],[7,8,-9]])
>>> m
matrix([[ 1, -2, 3],
        [ 0, 4, 5],
        [ 7, 8, -9]])

>>> # 矩阵转置
>>> m.T
matrix([[ 1, 0, 7],
        [-2, 4, 8],
        [ 3, 5, -9]])

>>> #逆矩阵
>>> m.I
matrix([[ 0.33043478, -0.02608696, 0.09565217],
        [-0.15217391, 0.13043478, 0.02173913],
        [ 0.12173913, 0.09565217, -0.0173913 ]])

>>> # 矩阵乘法  3行3列 *  3行1列 =3行1列
>>> v = np.matrix([[2],[3],[4]])
>>> v
matrix([[2],
        [3],
        [4]])
>>> m * v
matrix([[ 8],
        [32],
        [ 2]])
>>>

11.随机选择

(1)random 模块有大量的函数用来产生随机数和随机选择元素。 比如,要想从一个序列中随机的抽取一个元素,可以使用 random.choice() :

>>> import random
>>> values = [1, 2, 3, 4, 5, 6]
>>> random.choice(values)
2
>>> random.choice(values)
3
>>> random.choice(values)
1
>>> random.choice(values)
4
>>> random.choice(values)
6
>>>

(2)为了提取出N个不同元素的样本用来做进一步的操作,可以使用 random.sample() :

>>> random.sample(values, 2)
[6, 2]
>>> random.sample(values, 2)
[4, 3]
>>> random.sample(values, 3)
[4, 3, 1]
>>> random.sample(values, 3)
[5, 4, 1]
>>>

(3)仅仅只是想打乱序列中元素的顺序,可以使用 random.shuffle() :

>>> random.shuffle(values)
>>> values
[2, 4, 6, 5, 3, 1]
>>> random.shuffle(values)
>>> values
[3, 5, 2, 1, 6, 4]
>>>

(4)生成随机整数,请使用 random.randint() :

>>> random.randint(0,10)
2
>>> random.randint(0,10)
5
>>> random.randint(0,10)
0
>>> random.randint(0,10)
7
>>> random.randint(0,10)
10
>>> random.randint(0,10)
3
>>>

(5)生成0到1范围内均匀分布的浮点数,使用 random.random() :

>>> random.random()
0.9406677561675867
>>> random.random()
0.133129581343897
>>> random.random()
0.4144991136919316
>>>

(6)如果要获取N位随机位(二进制)的整数,使用 random.getrandbits() :

>>> random.getrandbits(200)
335837000776573622800628485064121869519521710558559406913275
>>>

12.基本的日期与时间转换

为了执行不同时间单位的转换和计算,请使用 datetime 模块。 比如,为了表示一个时间段,可以创建一个 timedelta 实例

>>> from datetime import timedelta
>>> a = timedelta(days=2, hours=6)
>>> b = timedelta(hours=4.5)
>>> c = a + b
>>> c.days
2
>>> c.seconds
37800
>>> c.seconds / 3600
10.5
>>> c.total_seconds() / 3600
58.5
>>>

datetime日期运算

>>> from datetime import datetime
>>> a = datetime(2012, 9, 23)
>>> print(a + timedelta(days=10))
2012-10-03 00:00:00
>>>
>>> b = datetime(2012, 12, 21)
>>> d = b - a
>>> d.days
89
>>> now = datetime.today()
>>> print(now)
2022-4-19 14:54:43.094063
>>> print(now + timedelta(minutes=10))
2022-4-19 15:04:43.094063
>>>

 datetime 会自动处理闰年

>>> a = datetime(2012, 3, 1)
>>> b = datetime(2012, 2, 28)
>>> a - b
datetime.timedelta(2)
>>> (a - b).days
2
>>> c = datetime(2013, 3, 1)
>>> d = datetime(2013, 2, 28)
>>> (c - d).days
1
>>>

13.计算上一个周五的日期

需要一个通用方法来计算一周中某一天上一次出现的日期,例如上一个周五的日期。

借助datetime:先将开始日期和目标日期映射到星期数组的位置上(星期一索引为0), 然后通过模运算计算出目标日期要经过多少天才能到达开始日期。然后用开始日期减去那个时间差即得到结果日期。

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
Topic: 最后的周五
Desc :
"""
from datetime import datetime, timedelta

weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
            'Friday', 'Saturday', 'Sunday']


def get_previous_byday(dayname, start_date=None):
    if start_date is None:
        start_date = datetime.today()
    day_num = start_date.weekday()
    day_num_target = weekdays.index(dayname)
    days_ago = (7 + day_num - day_num_target) % 7
    if days_ago == 0:
        days_ago = 7
    target_date = start_date - timedelta(days=days_ago)
    return target_date

def get_next_byday(dayname, start_date=None):
    if start_date is None:
        start_date = datetime.today()
    day_num = start_date.weekday()
    day_num_target = weekdays.index(dayname)
    days_ago = (7 + day_num - day_num_target) % 7
    if days_ago == 0:
        days_ago = 7
    target_date = start_date + timedelta(days=days_ago)
    return target_date

14.计算当前月份的日期范围

首先创建一个接受任意 datetime 对象并返回一个由当前月份开始日和下个月开始日(当月结束日)组成的元组对象。

from datetime import datetime, date, timedelta
import calendar

def get_month_range(start_date=None):
    if start_date is None:
    #先计算出一个对应月份第一天的日期。 一个快速的方法就是使用 date 或 datetime 对象的 replace() 方法简单的将 days 属性设置成1即可
        start_date = date.today().replace(day=1)
    #使用 calendar.monthrange() 函数来找出该月的总天数
    _, days_in_month = calendar.monthrange(start_date.year, start_date.month)
    end_date = start_date + timedelta(days=days_in_month)
    return (start_date, end_date)

a_day = timedelta(days=1)#获取当前月日期且设置为第一天
first_day, last_day = get_month_range()
while first_day < last_day:
	print(first_day)
	first_day += a_day
'''
2022-04-01
2022-04-02
2022-04-03
2022-04-04
2022-04-05
2022-04-06
2022-04-07
2022-04-08
2022-04-09
2022-04-10
2022-04-11
2022-04-12
2022-04-13
2022-04-14
2022-04-15
2022-04-16
2022-04-17
2022-04-18
2022-04-19
2022-04-20
2022-04-21
2022-04-22
2022-04-23
2022-04-24
2022-04-25
2022-04-26
2022-04-27
2022-04-28
2022-04-29
2022-04-30
'''

15.字符串转换为日期

datetime.strptime() 方法支持很多的格式化代码, 比如 %Y 代表4位数年份, %m 代表两位数月份。 还有一点值得注意的是这些格式化占位符也可以反过来使用,将日期输出为指定的格式字符串形式。

>>> from datetime import datetime
>>> text = '2019-04-20'
>>> y = datetime.strptime(text, '%Y-%m-%d')
>>> z = datetime.now()
>>> diff = z - y
>>> diff
datetime.timedelta(3, 77824, 177393)
>>>

strptime() 的性能要比你想象中的差很多 如果你要在代码中需要解析大量的日期并且已经知道了日期字符串的确切格式,可以自己实现一套解析方案来获取更好的性能。 比如,日期格式是 YYYY-MM-DD 

from datetime import datetime
def parse_ymd(s):
    year_s, mon_s, day_s = s.split('-')
    return datetime(int(year_s), int(mon_s), int(day_s))

16.结合时区的日期操作

对几乎所有涉及到时区的问题,你都应该使用 pytz 模块。这个包提供了Olson时区数据库, 它是时区信息的事实上的标准,在很多语言和操作系统里面都可以找到。

pytz 模块一个主要用途是将 datetime 库创建的简单日期对象本地化。

>>> from datetime import datetime
>>> from pytz import timezone
>>> d = datetime(2012, 12, 21, 9, 30, 0)
>>> print(d)
2012-12-21 09:30:00
>>>

>>> # Localize the date for Chicago
>>> central = timezone('US/Central')
>>> loc_d = central.localize(d)
>>> utc_d = loc_d.astimezone(pytz.utc)#转换为UTC,就不用去担心跟夏令时相关的问题
>>> print(utc_d)
2012-12-21 09:30:00-06:00
>>>

以上是关于Python数字日期和时间的主要内容,如果未能解决你的问题,请参考以下文章

Python数字日期和时间

华为python机试题目:明明的随机数汽水瓶求int型正整数在内存中存储时1的个数取近似值蛇形矩阵数据分类处理数字颠倒

获得前一年的近似值

Python进阶数字日期和时间

python3数字日期和时间

Python实战之数字日期和时间的高级处理