python - 使用日期时间显示最接近今天的日历项目

标签 python datetime

我有一个我想要的一个月日历项目的字典(日期作为“键”,项目以列表的形式作为“值”)以某种方式打印出来(该字典包含在代码中,分配给dct)。我只想显示当前日期(即今天)日期之后的项目。显示格式为:

day: item1, item2

我还希望这些项目仅跨越 5 行标准输出,每行 49 个字符宽(包括空格)。这是必要的,因为输出将显示在 conky(Linux 的应用程序)中。

由于一天可以有多个议程项目,因此必须将输出打包并打印在不止一行上。我希望代码通过仅选择那些项目可以容纳 5 行或更少行的日期来解决这一问题,而不是打印 5 天以及超过 5 行的关联项目。例如

day1: item1, item2
      item3
day2: item1
day3: item1,
      item2

即当天/之后 3 天打印 5 行,每行 49 个字符宽。超过 49 个字符的字符串将换行。

这是我为此编写的代码:

#!/usr/bin/env python

from datetime import date, timedelta, datetime
import heapq
import re
import textwrap

pattern_string = '(1[012]|[1-9]):[0-5][0-9](\\s)?(?i)(am|pm)'
pattern = re.compile(pattern_string)

# Explanation of pattern_string:
# ------------------------------
#(              #start of group #1
 #1[012]                #  start with 10, 11, 12
 #|             #  or
 #[1-9]             #  start with 1,2,...9
#)              #end of group #1
 #:             #   follow by a semi colon (:)
  #[0-5][0-9]           #     follw by 0..5 and 0..9, which means 00 to 59
            #(\\s)?     #       follow by a white space (optional)
                  #(?i)     #         next checking is case insensitive
                      #(am|pm)  #           follow by am or pm
# The 12-hour clock format is start from 0-12, then a semi colon (:) and follow by 00-59 , and end with am or pm.
# Time format that match:
# 1. "1:00am", "1:00 am","1:00 AM" ,
# 2. "1:00pm", "1:00 pm", "1:00 PM",
# 3. "12:50 pm"

d = date.today() # datetime.date(2013, 8, 11)
e = datetime.today() # datetime.datetime(2013, 8, 11, 5, 56, 28, 702926)
today = d.strftime('%a %b %d') # 'Sun Aug 11'

dct = {
'Thu Aug 01' : [' Weigh In'], 
'Thu Aug 08' : [' 8:00am', 'Serum uric acid test', '12:00pm', 'Make Cheesecake'], 
'Sun Aug 11' : [" Awais chotu's birthday", ' Car wash'], 
'Mon Aug 12' : ['10:00am', 'Start car for 10 minutes'], 
'Thu Aug 15' : [" Hooray! You're Facebook Free!", '10:00am', 'Start car for 10 minutes'], 
'Mon Aug 19' : ['10:00am', 'Start car for 10 minutes'], 
'Thu Aug 22' : ['10:00am', 'Start car for 10 minutes'], 
'Mon Aug 26' : ['10:00am', 'Start car for 10 minutes'], 
'Thu Aug 29' : ['10:00am', 'Start car for 10 minutes']
}

def join_time(lst):
    '''Searches for a time format string in supplied list and concatenates it + the event next to it as an single item
       to a list and returns that list'''
    mod_lst = []
    for number, item in enumerate(lst):
        if re.search(pattern, item):
            mod_lst.append(item + ' ' + lst[number+1]) # append the item (i.e time e.g '1:00am') and the item next to it (i.e. event)
            del lst[number+1]
        else:
            mod_lst.append(item)
    return mod_lst

def parse_date(datestring):
    return datetime.strptime(datestring + ' ' + str(date.today().year), "%a %b %d %Y") # returns a datetime obj for the time string; "Sun Aug 11" = datetime.datetime(1900, 8, 11, 0, 0)

deltas = [] # holds datetime.timedelta() objs; timedelta(days, seconds, microseconds)
val_len = []
key_len = {}

for key in dct:
    num = len(''.join(item for item in dct[key]))
    val_len.append(num) # calculate the combined len of all items in the 
                        # list which are the val of a key and add them to val_len
    if num > 37:
        key_len[key] = 2
    else:
        key_len[key] = 1

# val_len = [31, 9, 61, 31, 31, 49, 31, 32, 31]
# key_len = {'Sun Aug 11': 1, 'Mon Aug 12': 1, 'Thu Aug 01': 1, 'Thu Aug 15': 2, 'Thu Aug 22': 1, 'Mon Aug 19': 1, 'Thu Aug 08': 2, 'Mon Aug 26': 1, 'Thu Aug 29': 1}

counter = 0
for eachLen in val_len:
    if eachLen > 37:
        counter = counter + 2
    else:
        counter = counter + 1

# counter = 11

if counter > 5: # because we want only those 5 events in our conky output which are closest to today
    n = counter - 5 # n = 6, these no of event lines should be skipped

    for key in dct:
        deltas.append(e - parse_date(key)) # today - key date (e.g. 'Sun Aug 11') ---> datetime.datetime(2013, 8, 11, 5, 56, 28, 702926) - datetime.datetime(1900, 8, 11, 0, 0)

    # TODO: 'n' no of event lines should be skipped, NOT n no of days!  
    for key in sorted(dct, key=parse_date): # sorted() returns ['Thu Aug 01', 'Thu Aug 08', 'Sun Aug 11', 'Mon Aug 12', 'Thu Aug 15', 'Mon Aug 19', 'Thu Aug 22', 'Mon Aug 26', 'Thu Aug 29']
        tdelta = e - parse_date(key)
        if tdelta in heapq.nlargest(n, deltas): # heapq.nlargest(x, iterable[, key]); returns list of 'x' no. of largest items in iterable
            pass                                # In this case it should return a list of top 6 largest timedeltas; if the tdelta is in 
                                                # that list, it means its not amongst the 5 events we want to print
        else:
            if key == today:
                value = dct[key]
                val1 = '${color green}' + key + '$color: ' 
                mod_val = join_time(value) 
                val2 = textwrap.wrap(', '.join(item for item in mod_val), 37)
                print val1 + '${color 40E0D0}' + '$color\n          ${color 40E0D0}'.join(item for item in val2) + '$color'
            else:
                value = dct[key]
                mod_val = join_time(value)
                output = key + ': ' + ', '.join(item for item in mod_val)
                print '\n           '.join(textwrap.wrap(output, 49))

else:   
    for key in sorted(dct, key=parse_date):
        if key == today:
            value = dct[key]
            val1 = '${color green}' + key + '$color: ' 
            mod_val = join_time(value) 
            val2 = textwrap.wrap(', '.join(item for item in mod_val), 37)
            print val1 + '${color 40E0D0}' + '$color\n          ${color 40E0D0}'.join(item for item in val2) + '$color'
        else:
            value = dct[key]
            mod_val = join_time(value)
            output = key + ': ' + ', '.join(item for item in mod_val)
            print '\n           '.join(textwrap.wrap(output, 49))

结果是:

Thu Aug 22: 10:00am Start car for 10 minutes
Mon Aug 26: 10:00am Start car for 10 minutes
Thu Aug 29: 10:00am Start car for 10 minutes

我已经对代码进行了大量注释,因此应该不难弄清楚它是如何工作的。我基本上是使用日期时间计算距离当天最远的日子,并跳过那些日子及其项目。该代码通常运行良好,但有时却运行不佳。在这种情况下,输出应该是:

Mon Aug 19: 10:00am Start car for 10 minutes
Thu Aug 22: 10:00am Start car for 10 minutes
Mon Aug 26: 10:00am Start car for 10 minutes
Thu Aug 29: 10:00am Start car for 10 minutes

因为这些是当天(8 月 16 日星期五)之后的几天,其项目可容纳 5 行。 如何修复它以跳过 n 行而不是距今天最远的天数?

我正在考虑使用 key_len 字典以某种方式进一步过滤输出,方法是仅打印那些天的项目长度总和<或= 5的项目。 ..

我被困住了。

最佳答案

很难说出你在这里问的是什么,而且你的代码非常困惑。

但是,在给定示例中获得错误输出的原因非常明显,并且与代码中的 TODO 注释相匹配,因此我假设这是您唯一的部分询问的是:

 # TODO: 'n' no of event lines should be skipped, NOT n no of days!

我不明白为什么你想跳到今天之后的最后 5 行而不是前 5 行,但我假设你有一些充分的理由。

解决这个问题的最简单方法就是相反地执行它们,将这些行添加到一个字符串中,而不是直接打印它们,当达到 5 行时停止,然后打印字符串。 (这也将节省一遍又一遍地重新构建堆的浪费,等等)

例如,像这样:

outlines = []
for key in sorted(dct, key=parse_date, reverse=True): # sorted() returns ['Thu Aug 01', 'Thu Aug 08', 'Sun Aug 11', 'Mon Aug 12', 'Thu Aug 15', 'Mon Aug 19', 'Thu Aug 22', 'Mon Aug 26', 'Thu Aug 29']
    if parse_date(key) < parse_date(today):
        break
    tdelta = e - parse_date(key)
    if key == today:
        value = dct[key]
        val1 = '${color green}' + key + '$color: ' 
        mod_val = join_time(value) 
        val2 = textwrap.wrap(', '.join(item for item in mod_val), 37)
        outstr = val1 + '${color 40E0D0}' + '$color\n          ${color 40E0D0}'.join(item for item in val2) + '$color'
        outlines[:0] = outstr.splitlines()
    else:
        value = dct[key]
        mod_val = join_time(value)
        output = key + ': ' + ', '.join(item for item in mod_val)
        outstr = '\n           '.join(textwrap.wrap(output, 49))
        outlines[:0] = outstr.splitlines()
    if len(outlines) >= 5:
        break
print '\n'.join(outlines)

有很多方法可以简化这个过程。例如,不要传递日期的字符串表示形式并到处使用 parse_date,而只需传递日期,并在最后格式化一次。使用字符串格式而不是 120 个字符的多重串联表达式。构建一次数据结构并使用它们,而不是在需要的地方一遍又一遍地重建它们。等等。但这应该是让它工作所需的全部。

关于python - 使用日期时间显示最接近今天的日历项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18282300/

相关文章:

c# - 在 Select 语句中将 DateTime 转换为 Unix 时间戳?

python - 嵌套链与重复信息

python - 根据存储在另一个列表中的索引替换列表列表中的元素

python - 使用 pyODBC 连接到 ODBC

javascript - 如何在MarkLogic中获取两个xs.date的天数差异?

c# - 在 C# 中转换日期字符串

javascript - 将时间戳从时区转换为 UTC 时间戳?

python - 为 django 密码重置表单添加样式

python - Python 中 CSV 列的列表

Python - 在 UTC 中获取时区感知当前时间的最简单和最连贯的方法?