clox 0.6__py3-none-any.whl → 0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of clox might be problematic. Click here for more details.
- clox/functions.py +32 -10
- clox/jcalendar.py +359 -0
- clox/params.py +3 -1
- {clox-0.6.dist-info → clox-0.7.dist-info}/METADATA +23 -5
- clox-0.7.dist-info/RECORD +12 -0
- {clox-0.6.dist-info → clox-0.7.dist-info}/WHEEL +1 -1
- clox-0.6.dist-info/RECORD +0 -11
- {clox-0.6.dist-info → clox-0.7.dist-info}/AUTHORS.md +0 -0
- {clox-0.6.dist-info → clox-0.7.dist-info}/LICENSE +0 -0
- {clox-0.6.dist-info → clox-0.7.dist-info}/entry_points.txt +0 -0
- {clox-0.6.dist-info → clox-0.7.dist-info}/top_level.txt +0 -0
clox/functions.py
CHANGED
|
@@ -3,17 +3,19 @@
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
import time
|
|
6
|
-
import
|
|
6
|
+
from calendar import TextCalendar as GregorianCalendar
|
|
7
7
|
import random
|
|
8
8
|
import datetime
|
|
9
|
+
import jdatetime
|
|
9
10
|
import argparse
|
|
10
11
|
import pytz
|
|
11
12
|
from art import tprint
|
|
13
|
+
from .jcalendar import TextCalendar as JalaliCalendar
|
|
12
14
|
from .params import HORIZONTAL_TIME_24H_FORMATS, VERTICAL_TIME_24H_FORMATS
|
|
13
15
|
from .params import HORIZONTAL_TIME_12H_FORMATS, VERTICAL_TIME_12H_FORMATS
|
|
14
16
|
from .params import TIMEZONES_LIST, CLOX_VERSION, DATE_FORMAT
|
|
15
17
|
from .params import ADDITIONAL_INFO, EXIT_MESSAGE
|
|
16
|
-
from .params import FACES_MAP, FACES_LIST, CALENDAR_LIST
|
|
18
|
+
from .params import FACES_MAP, FACES_LIST, CALENDAR_LIST, DATE_SYSTEMS_LIST
|
|
17
19
|
from .params import HORIZONTAL_FACES_LIST_EXAMPLE, VERTICAL_FACES_LIST_EXAMPLE
|
|
18
20
|
from .params import CLOX_OVERVIEW, CLOX_REPO
|
|
19
21
|
|
|
@@ -86,7 +88,7 @@ def show_timezones_list():
|
|
|
86
88
|
print("{index}. {timezone}".format(index=index, timezone=timezone))
|
|
87
89
|
|
|
88
90
|
|
|
89
|
-
def print_calendar(mode="month", timezone=None, v_shift=0, h_shift=0):
|
|
91
|
+
def print_calendar(mode="month", timezone=None, v_shift=0, h_shift=0, date_system="gregorian"):
|
|
90
92
|
"""
|
|
91
93
|
Print calendar.
|
|
92
94
|
|
|
@@ -98,8 +100,15 @@ def print_calendar(mode="month", timezone=None, v_shift=0, h_shift=0):
|
|
|
98
100
|
:type v_shift: int
|
|
99
101
|
:param h_shift: horizontal shift
|
|
100
102
|
:type h_shift: int
|
|
103
|
+
:param date_system: date system
|
|
104
|
+
:type date_system: str
|
|
101
105
|
:return: None
|
|
102
106
|
"""
|
|
107
|
+
datetime_lib = datetime
|
|
108
|
+
calendar_obj = GregorianCalendar()
|
|
109
|
+
if date_system == "jalali":
|
|
110
|
+
datetime_lib = jdatetime
|
|
111
|
+
calendar_obj = JalaliCalendar()
|
|
103
112
|
tz = None
|
|
104
113
|
timezone_str = "Local"
|
|
105
114
|
if timezone is not None:
|
|
@@ -107,16 +116,16 @@ def print_calendar(mode="month", timezone=None, v_shift=0, h_shift=0):
|
|
|
107
116
|
tz = pytz.timezone(timezone)
|
|
108
117
|
v_shift = max(0, v_shift)
|
|
109
118
|
h_shift = max(0, h_shift)
|
|
110
|
-
datetime_now =
|
|
119
|
+
datetime_now = datetime_lib.datetime.now(tz=tz)
|
|
111
120
|
current_date = datetime_now.strftime(DATE_FORMAT)
|
|
112
121
|
print('\n' * v_shift, end='')
|
|
113
122
|
print(" " * h_shift, end='')
|
|
114
123
|
print("Today: {date}".format(date=current_date))
|
|
115
124
|
print(" " * h_shift, end='')
|
|
116
125
|
print("Timezone: {timezone}\n".format(timezone=timezone_str))
|
|
117
|
-
calendar_str =
|
|
126
|
+
calendar_str = calendar_obj.formatmonth(datetime_now.year, datetime_now.month)
|
|
118
127
|
if mode == "year":
|
|
119
|
-
calendar_str =
|
|
128
|
+
calendar_str = calendar_obj.formatyear(datetime_now.year)
|
|
120
129
|
print("\n".join([" " * h_shift + x for x in calendar_str.split("\n")]))
|
|
121
130
|
|
|
122
131
|
|
|
@@ -129,7 +138,8 @@ def run_clock(
|
|
|
129
138
|
vertical=False,
|
|
130
139
|
hide_date=False,
|
|
131
140
|
hide_timezone=False,
|
|
132
|
-
am_pm=False
|
|
141
|
+
am_pm=False,
|
|
142
|
+
date_system="gregorian"):
|
|
133
143
|
"""
|
|
134
144
|
Run clock.
|
|
135
145
|
|
|
@@ -151,8 +161,13 @@ def run_clock(
|
|
|
151
161
|
:type hide_timezone: bool
|
|
152
162
|
:param am_pm: AM/PM mode flag
|
|
153
163
|
:type am_pm: bool
|
|
164
|
+
:param date_system: date system
|
|
165
|
+
:type date_system: str
|
|
154
166
|
:return: None
|
|
155
167
|
"""
|
|
168
|
+
datetime_lib = datetime
|
|
169
|
+
if date_system == "jalali":
|
|
170
|
+
datetime_lib = jdatetime
|
|
156
171
|
format_index = 0
|
|
157
172
|
time_formats = HORIZONTAL_TIME_12H_FORMATS if am_pm else HORIZONTAL_TIME_24H_FORMATS
|
|
158
173
|
if vertical:
|
|
@@ -169,7 +184,7 @@ def run_clock(
|
|
|
169
184
|
clear_screen()
|
|
170
185
|
print('\n' * v_shift, end='')
|
|
171
186
|
print(" " * h_shift, end='')
|
|
172
|
-
datetime_now =
|
|
187
|
+
datetime_now = datetime_lib.datetime.now(tz=tz)
|
|
173
188
|
current_time = datetime_now.strftime(time_formats[format_index])
|
|
174
189
|
current_date = datetime_now.strftime(DATE_FORMAT)
|
|
175
190
|
tprint(current_time, font=face, sep="\n" + " " * h_shift)
|
|
@@ -206,6 +221,7 @@ def main():
|
|
|
206
221
|
parser.add_argument('--hide-timezone', help='hide timezone', nargs="?", const=1)
|
|
207
222
|
parser.add_argument('--am-pm', help='AM/PM mode', nargs="?", const=1)
|
|
208
223
|
parser.add_argument('--calendar', help='calendar mode', type=str, choices=CALENDAR_LIST)
|
|
224
|
+
parser.add_argument('--date-system', help='date system', type=str, choices=DATE_SYSTEMS_LIST, default="gregorian")
|
|
209
225
|
args = parser.parse_args()
|
|
210
226
|
if args.version:
|
|
211
227
|
print(CLOX_VERSION)
|
|
@@ -216,7 +232,12 @@ def main():
|
|
|
216
232
|
elif args.timezones_list:
|
|
217
233
|
show_timezones_list()
|
|
218
234
|
elif args.calendar:
|
|
219
|
-
print_calendar(
|
|
235
|
+
print_calendar(
|
|
236
|
+
mode=args.calendar,
|
|
237
|
+
timezone=args.timezone,
|
|
238
|
+
h_shift=args.h_shift,
|
|
239
|
+
v_shift=args.v_shift,
|
|
240
|
+
date_system=args.date_system)
|
|
220
241
|
else:
|
|
221
242
|
try:
|
|
222
243
|
run_clock(
|
|
@@ -228,6 +249,7 @@ def main():
|
|
|
228
249
|
vertical=args.vertical,
|
|
229
250
|
hide_date=args.hide_date,
|
|
230
251
|
hide_timezone=args.hide_timezone,
|
|
231
|
-
am_pm=args.am_pm
|
|
252
|
+
am_pm=args.am_pm,
|
|
253
|
+
date_system=args.date_system)
|
|
232
254
|
except (KeyboardInterrupt, EOFError):
|
|
233
255
|
print(EXIT_MESSAGE)
|
clox/jcalendar.py
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""clox jalali calendar."""
|
|
3
|
+
# Reference: https://github.com/IKermani/jcalendar
|
|
4
|
+
import datetime
|
|
5
|
+
from itertools import repeat
|
|
6
|
+
import jdatetime
|
|
7
|
+
|
|
8
|
+
# Exception raised for bad input (with string parameter for details)
|
|
9
|
+
error = ValueError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Exceptions raised for bad input
|
|
13
|
+
class IllegalMonthError(ValueError):
|
|
14
|
+
"""Illegal month error."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, month):
|
|
17
|
+
"""Initiate."""
|
|
18
|
+
self.month = month
|
|
19
|
+
|
|
20
|
+
def __str__(self):
|
|
21
|
+
"""Return string representation."""
|
|
22
|
+
return "bad month number %r; must be 1-12" % self.month
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class IllegalWeekdayError(ValueError):
|
|
26
|
+
"""Illegal weekday error."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, weekday):
|
|
29
|
+
"""Initiate."""
|
|
30
|
+
self.weekday = weekday
|
|
31
|
+
|
|
32
|
+
def __str__(self):
|
|
33
|
+
"""Return string representation."""
|
|
34
|
+
return "bad weekday number %r; must be 0 (Shanbe) to 6 (Jom'e)" % self.weekday
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Constants for months referenced later
|
|
38
|
+
January = 1
|
|
39
|
+
February = 2
|
|
40
|
+
|
|
41
|
+
Farvardin = 1
|
|
42
|
+
Esfand = 12
|
|
43
|
+
|
|
44
|
+
# Number of days per month (except for Esfand in leap years)
|
|
45
|
+
mdays = [0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29]
|
|
46
|
+
|
|
47
|
+
# Full and abbreviated names of weekdays
|
|
48
|
+
day_name = jdatetime.date.j_weekdays_en
|
|
49
|
+
day_abbr = jdatetime.date.j_weekdays_short_en
|
|
50
|
+
# day_abbr = ['Sh', 'Ye', 'Do', 'Se', 'Ch', 'Pa', 'Jo']
|
|
51
|
+
|
|
52
|
+
# Full and abbreviated names of months (1-based arrays!!!)
|
|
53
|
+
month_name = [0] + jdatetime.date.j_months_en
|
|
54
|
+
month_abbr = [0] + jdatetime.date.j_months_short_en
|
|
55
|
+
|
|
56
|
+
# Constants for weekdays
|
|
57
|
+
(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
|
|
58
|
+
(DOSHANBE, SESHANBE, CHAHARSHANBE, PANJSHANBE, JOME, SHANBE, YEKSHANBE) = range(7)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def isleap(year):
|
|
62
|
+
"""Return True for leap years, False for non-leap years."""
|
|
63
|
+
return jdatetime.date(year, 1, 1).isleap()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def leapdays(y1, y2):
|
|
67
|
+
"""Return number of leap years in range [y1, y2)."""
|
|
68
|
+
leapdays = 0
|
|
69
|
+
|
|
70
|
+
for year in range(y1, y2):
|
|
71
|
+
if isleap(year):
|
|
72
|
+
leapdays += 1
|
|
73
|
+
|
|
74
|
+
return leapdays
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def weekday(year, month, day):
|
|
78
|
+
"""Return week-day (0-6 ~ Mon-Sun)."""
|
|
79
|
+
if not datetime.MINYEAR <= year <= datetime.MAXYEAR:
|
|
80
|
+
year = 2000 + year % 400
|
|
81
|
+
return jdatetime.date(year, month, day).weekday()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def monthrange(year, month):
|
|
85
|
+
"""Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month."""
|
|
86
|
+
if not 1 <= month <= 12:
|
|
87
|
+
raise IllegalMonthError(month)
|
|
88
|
+
day1 = weekday(year, month, 1)
|
|
89
|
+
ndays = mdays[month] + (month == Esfand and isleap(year))
|
|
90
|
+
return day1, ndays
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _monthlen(year, month):
|
|
94
|
+
"""Return length of month."""
|
|
95
|
+
return mdays[month] + (month == Esfand and isleap(year))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _prevmonth(year, month):
|
|
99
|
+
"""Return previous month."""
|
|
100
|
+
if month == 1:
|
|
101
|
+
return year - 1, 12
|
|
102
|
+
else:
|
|
103
|
+
return year, month - 1
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _nextmonth(year, month):
|
|
107
|
+
"""Return next month."""
|
|
108
|
+
if month == 12:
|
|
109
|
+
return year + 1, 1
|
|
110
|
+
else:
|
|
111
|
+
return year, month + 1
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Calendar(object):
|
|
115
|
+
"""Base calendar class. This class doesn't do any formatting. It simply provides data to subclasses."""
|
|
116
|
+
|
|
117
|
+
def __init__(self, firstweekday=0):
|
|
118
|
+
"""Initiate."""
|
|
119
|
+
self.firstweekday = firstweekday # 0 = Doshanbe, 6 = Yekshanbe
|
|
120
|
+
|
|
121
|
+
def getfirstweekday(self):
|
|
122
|
+
"""Get first weekday."""
|
|
123
|
+
return self._firstweekday % 7
|
|
124
|
+
|
|
125
|
+
def setfirstweekday(self, firstweekday):
|
|
126
|
+
"""Set first weekday."""
|
|
127
|
+
self._firstweekday = firstweekday
|
|
128
|
+
|
|
129
|
+
firstweekday = property(getfirstweekday, setfirstweekday)
|
|
130
|
+
|
|
131
|
+
def iterweekdays(self):
|
|
132
|
+
"""Return an iterator for one week of weekday numbers starting with the configured first one."""
|
|
133
|
+
for i in range(self.firstweekday, self.firstweekday + 7):
|
|
134
|
+
yield i % 7
|
|
135
|
+
|
|
136
|
+
def itermonthdates(self, year, month):
|
|
137
|
+
"""Return an iterator for one month."""
|
|
138
|
+
for y, m, d in self.itermonthdays3(year, month):
|
|
139
|
+
yield jdatetime.date(y, m, d)
|
|
140
|
+
|
|
141
|
+
def itermonthdays(self, year, month):
|
|
142
|
+
"""Like itermonthdates(), but will yield day numbers. For days outside the specified month the day number is 0."""
|
|
143
|
+
day1, ndays = monthrange(year, month)
|
|
144
|
+
days_before = (day1 - self.firstweekday) % 7
|
|
145
|
+
yield from repeat(0, days_before)
|
|
146
|
+
yield from range(1, ndays + 1)
|
|
147
|
+
days_after = (self.firstweekday - day1 - ndays) % 7
|
|
148
|
+
yield from repeat(0, days_after)
|
|
149
|
+
|
|
150
|
+
def itermonthdays2(self, year, month):
|
|
151
|
+
"""Like itermonthdates(), but will yield (day number, weekday number) tuples. For days outside the specified month the day number is 0."""
|
|
152
|
+
for i, d in enumerate(self.itermonthdays(year, month), self.firstweekday):
|
|
153
|
+
yield d, i % 7
|
|
154
|
+
|
|
155
|
+
def itermonthdays3(self, year, month):
|
|
156
|
+
"""Like itermonthdates(), but will yield (year, month, day) tuples. Can be used for dates outside of datetime.date range."""
|
|
157
|
+
day1, ndays = monthrange(year, month)
|
|
158
|
+
days_before = (day1 - self.firstweekday) % 7
|
|
159
|
+
days_after = (self.firstweekday - day1 - ndays) % 7
|
|
160
|
+
y, m = _prevmonth(year, month)
|
|
161
|
+
end = _monthlen(y, m) + 1
|
|
162
|
+
for d in range(end - days_before, end):
|
|
163
|
+
yield y, m, d
|
|
164
|
+
for d in range(1, ndays + 1):
|
|
165
|
+
yield year, month, d
|
|
166
|
+
y, m = _nextmonth(year, month)
|
|
167
|
+
for d in range(1, days_after + 1):
|
|
168
|
+
yield y, m, d
|
|
169
|
+
|
|
170
|
+
def itermonthdays4(self, year, month):
|
|
171
|
+
"""Like itermonthdates(), but will yield (year, month, day, day_of_week) tuples. Can be used for dates outside of datetime.date range."""
|
|
172
|
+
for i, (y, m, d) in enumerate(self.itermonthdays3(year, month)):
|
|
173
|
+
yield y, m, d, (self.firstweekday + i) % 7
|
|
174
|
+
|
|
175
|
+
def monthdatescalendar(self, year, month):
|
|
176
|
+
"""Return a matrix (list of lists) representing a month's calendar.Each row represents a week; week entries are datetime.date values."""
|
|
177
|
+
dates = list(self.itermonthdates(year, month))
|
|
178
|
+
return [dates[i:i + 7] for i in range(0, len(dates), 7)]
|
|
179
|
+
|
|
180
|
+
def monthdays2calendar(self, year, month):
|
|
181
|
+
"""Return a matrix representing a month's calendar."""
|
|
182
|
+
days = list(self.itermonthdays2(year, month))
|
|
183
|
+
return [days[i:i + 7] for i in range(0, len(days), 7)]
|
|
184
|
+
|
|
185
|
+
def monthdayscalendar(self, year, month):
|
|
186
|
+
"""Return a matrix representing a month's calendar."""
|
|
187
|
+
days = list(self.itermonthdays(year, month))
|
|
188
|
+
return [days[i:i + 7] for i in range(0, len(days), 7)]
|
|
189
|
+
|
|
190
|
+
def yeardatescalendar(self, year, width=3):
|
|
191
|
+
"""Return the data for the specified year ready for formatting."""
|
|
192
|
+
months = [
|
|
193
|
+
self.monthdatescalendar(year, i)
|
|
194
|
+
for i in range(Farvardin, Farvardin + 12)
|
|
195
|
+
]
|
|
196
|
+
return [months[i:i + width] for i in range(0, len(months), width)]
|
|
197
|
+
|
|
198
|
+
def yeardays2calendar(self, year, width=3):
|
|
199
|
+
"""Return the data for the specified year ready for formatting."""
|
|
200
|
+
months = [
|
|
201
|
+
self.monthdays2calendar(year, i)
|
|
202
|
+
for i in range(Farvardin, Farvardin + 12)
|
|
203
|
+
]
|
|
204
|
+
return [months[i:i + width] for i in range(0, len(months), width)]
|
|
205
|
+
|
|
206
|
+
def yeardayscalendar(self, year, width=3):
|
|
207
|
+
"""Return the data for the specified year ready for formatting."""
|
|
208
|
+
months = [
|
|
209
|
+
self.monthdayscalendar(year, i)
|
|
210
|
+
for i in range(Farvardin, Farvardin + 12)
|
|
211
|
+
]
|
|
212
|
+
return [months[i:i + width] for i in range(0, len(months), width)]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class TextCalendar(Calendar):
|
|
216
|
+
"""Subclass of Calendar that outputs a calendar as a simple plain text similar to the UNIX program cal."""
|
|
217
|
+
|
|
218
|
+
def prweek(self, theweek, width):
|
|
219
|
+
"""Print a single week (no newline)."""
|
|
220
|
+
print(self.formatweek(theweek, width), end='')
|
|
221
|
+
|
|
222
|
+
def formatday(self, day, weekday, width):
|
|
223
|
+
"""Return a formatted day."""
|
|
224
|
+
if day == 0:
|
|
225
|
+
s = ''
|
|
226
|
+
else:
|
|
227
|
+
s = '%2i' % day # right-align single-digit days
|
|
228
|
+
return s.center(width)
|
|
229
|
+
|
|
230
|
+
def formatweek(self, theweek, width):
|
|
231
|
+
"""Return a single week in a string (no newline)."""
|
|
232
|
+
return ' '.join(self.formatday(d, wd, width) for (d, wd) in theweek)
|
|
233
|
+
|
|
234
|
+
def formatweekday(self, day, width):
|
|
235
|
+
"""Return a formatted week day name."""
|
|
236
|
+
if width >= 9:
|
|
237
|
+
names = day_name
|
|
238
|
+
else:
|
|
239
|
+
names = day_abbr
|
|
240
|
+
return names[day][:width].center(width)
|
|
241
|
+
|
|
242
|
+
def formatweekheader(self, width):
|
|
243
|
+
"""Return a header for a week."""
|
|
244
|
+
return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays())
|
|
245
|
+
|
|
246
|
+
def formatmonthname(self, theyear, themonth, width, withyear=True):
|
|
247
|
+
"""Return a formatted month name."""
|
|
248
|
+
s = month_name[themonth]
|
|
249
|
+
if withyear:
|
|
250
|
+
s = "%s %r" % (s, theyear)
|
|
251
|
+
return s.center(width)
|
|
252
|
+
|
|
253
|
+
def prmonth(self, theyear, themonth, w=0, l=0):
|
|
254
|
+
"""Print a month's calendar."""
|
|
255
|
+
print(self.formatmonth(theyear, themonth, w, l), end='')
|
|
256
|
+
|
|
257
|
+
def formatmonth(self, theyear, themonth, w=0, l=0):
|
|
258
|
+
"""Return a month's calendar string (multi-line)."""
|
|
259
|
+
w = max(2, w)
|
|
260
|
+
l = max(1, l)
|
|
261
|
+
s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
|
|
262
|
+
s = s.rstrip()
|
|
263
|
+
s += '\n' * l
|
|
264
|
+
s += self.formatweekheader(w).rstrip()
|
|
265
|
+
s += '\n' * l
|
|
266
|
+
for week in self.monthdays2calendar(theyear, themonth):
|
|
267
|
+
s += self.formatweek(week, w).rstrip()
|
|
268
|
+
s += '\n' * l
|
|
269
|
+
return s
|
|
270
|
+
|
|
271
|
+
def formatyear(self, theyear, w=2, l=1, c=6, m=3):
|
|
272
|
+
"""Return a year's calendar as a multi-line string."""
|
|
273
|
+
w = max(2, w)
|
|
274
|
+
l = max(1, l)
|
|
275
|
+
c = max(2, c)
|
|
276
|
+
colwidth = (w + 1) * 7 - 1
|
|
277
|
+
v = []
|
|
278
|
+
a = v.append
|
|
279
|
+
a(repr(theyear).center(colwidth * m + c * (m - 1)).rstrip())
|
|
280
|
+
a('\n' * l)
|
|
281
|
+
header = self.formatweekheader(w)
|
|
282
|
+
for (i, row) in enumerate(self.yeardays2calendar(theyear, m)):
|
|
283
|
+
# months in this row
|
|
284
|
+
months = range(m * i + 1, min(m * (i + 1) + 1, 13))
|
|
285
|
+
a('\n' * l)
|
|
286
|
+
names = (self.formatmonthname(theyear, k, colwidth, False)
|
|
287
|
+
for k in months)
|
|
288
|
+
a(formatstring(names, colwidth, c).rstrip())
|
|
289
|
+
a('\n' * l)
|
|
290
|
+
headers = (header for k in months)
|
|
291
|
+
a(formatstring(headers, colwidth, c).rstrip())
|
|
292
|
+
a('\n' * l)
|
|
293
|
+
# max number of weeks for this row
|
|
294
|
+
height = max(len(cal) for cal in row)
|
|
295
|
+
for j in range(height):
|
|
296
|
+
weeks = []
|
|
297
|
+
for cal in row:
|
|
298
|
+
if j >= len(cal):
|
|
299
|
+
weeks.append('')
|
|
300
|
+
else:
|
|
301
|
+
weeks.append(self.formatweek(cal[j], w))
|
|
302
|
+
a(formatstring(weeks, colwidth, c).rstrip())
|
|
303
|
+
a('\n' * l)
|
|
304
|
+
return ''.join(v)
|
|
305
|
+
|
|
306
|
+
def pryear(self, theyear, w=0, l=0, c=6, m=3):
|
|
307
|
+
"""Print a year's calendar."""
|
|
308
|
+
print(self.formatyear(theyear, w, l, c, m), end='')
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
c = TextCalendar()
|
|
312
|
+
|
|
313
|
+
firstweekday = c.getfirstweekday
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def setfirstweekday(firstweekday):
|
|
317
|
+
"""Set first weekday."""
|
|
318
|
+
if not DOSHANBE <= firstweekday <= YEKSHANBE:
|
|
319
|
+
raise IllegalWeekdayError(firstweekday)
|
|
320
|
+
c.firstweekday = firstweekday
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
monthcalendar = c.monthdayscalendar
|
|
324
|
+
prweek = c.prweek
|
|
325
|
+
week = c.formatweek
|
|
326
|
+
weekheader = c.formatweekheader
|
|
327
|
+
prmonth = c.prmonth
|
|
328
|
+
month = c.formatmonth
|
|
329
|
+
calendar = c.formatyear
|
|
330
|
+
prcal = c.pryear
|
|
331
|
+
|
|
332
|
+
# Spacing of month columns for multi-column year calendar
|
|
333
|
+
_colwidth = 7 * 3 - 1 # Amount printed by prweek()
|
|
334
|
+
_spacing = 6 # Number of spaces between columns
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def format(cols, colwidth=_colwidth, spacing=_spacing):
|
|
338
|
+
"""Print multi-column formatting for year calendars."""
|
|
339
|
+
print(formatstring(cols, colwidth, spacing))
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def formatstring(cols, colwidth=_colwidth, spacing=_spacing):
|
|
343
|
+
"""Return a string formatted from n strings, centered within n columns."""
|
|
344
|
+
spacing *= ' '
|
|
345
|
+
return spacing.join(c.center(colwidth) for c in cols)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
EPOCH = 1970
|
|
349
|
+
_EPOCH_ORD = jdatetime.date(EPOCH, 1, 1).toordinal()
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def timegm(tuple):
|
|
353
|
+
"""Unrelated but handy function to calculate Unix timestamp from GMT."""
|
|
354
|
+
year, month, day, hour, minute, second = tuple[:6]
|
|
355
|
+
days = jdatetime.date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
|
|
356
|
+
hours = days * 24 + hour
|
|
357
|
+
minutes = hours * 60 + minute
|
|
358
|
+
seconds = minutes * 60 + second
|
|
359
|
+
return seconds
|
clox/params.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""clox params."""
|
|
3
3
|
import pytz
|
|
4
4
|
|
|
5
|
-
CLOX_VERSION = "0.
|
|
5
|
+
CLOX_VERSION = "0.7"
|
|
6
6
|
|
|
7
7
|
CLOX_OVERVIEW = '''
|
|
8
8
|
Clox is a terminal-based clock application designed for terminal enthusiasts who appreciate simplicity,
|
|
@@ -58,3 +58,5 @@ FACES_MAP = {
|
|
|
58
58
|
FACES_LIST = [-1] + sorted(FACES_MAP)
|
|
59
59
|
|
|
60
60
|
CALENDAR_LIST = ["month", "year"]
|
|
61
|
+
|
|
62
|
+
DATE_SYSTEMS_LIST = ["gregorian", "jalali"]
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: clox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7
|
|
4
4
|
Summary: A Geeky Clock for Terminal Enthusiasts
|
|
5
5
|
Home-page: https://github.com/sepandhaghighi/clox
|
|
6
|
-
Download-URL: https://github.com/sepandhaghighi/clox/tarball/v0.
|
|
6
|
+
Download-URL: https://github.com/sepandhaghighi/clox/tarball/v0.7
|
|
7
7
|
Author: Sepand Haghighi
|
|
8
8
|
Author-email: me@sepand.tech
|
|
9
9
|
License: MIT
|
|
@@ -32,6 +32,7 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
License-File: LICENSE
|
|
33
33
|
License-File: AUTHORS.md
|
|
34
34
|
Requires-Dist: art>=5.3
|
|
35
|
+
Requires-Dist: jdatetime>=3.8.2
|
|
35
36
|
Requires-Dist: pytz>=2019.2
|
|
36
37
|
Dynamic: author
|
|
37
38
|
Dynamic: author-email
|
|
@@ -103,13 +104,13 @@ Clox is a terminal-based clock application designed for terminal enthusiasts who
|
|
|
103
104
|
## Installation
|
|
104
105
|
|
|
105
106
|
### Source Code
|
|
106
|
-
- Download [Version 0.
|
|
107
|
+
- Download [Version 0.7](https://github.com/sepandhaghighi/clox/archive/v0.7.zip) or [Latest Source](https://github.com/sepandhaghighi/clox/archive/dev.zip)
|
|
107
108
|
- `pip install .`
|
|
108
109
|
|
|
109
110
|
### PyPI
|
|
110
111
|
|
|
111
112
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
112
|
-
- `pip install clox==0.
|
|
113
|
+
- `pip install clox==0.7`
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
## Usage
|
|
@@ -209,6 +210,16 @@ In this mode, the calendar will be displayed
|
|
|
209
210
|
clox --calendar=month
|
|
210
211
|
```
|
|
211
212
|
|
|
213
|
+
### Date System
|
|
214
|
+
|
|
215
|
+
ℹ️ Valid choices: [`gregorian`, `jalali`]
|
|
216
|
+
|
|
217
|
+
ℹ️ The default date system is `gregorian`
|
|
218
|
+
|
|
219
|
+
```console
|
|
220
|
+
clox --date-system=jalali
|
|
221
|
+
```
|
|
222
|
+
|
|
212
223
|
## Screen Record
|
|
213
224
|
|
|
214
225
|
<div align="center">
|
|
@@ -267,6 +278,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
267
278
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
268
279
|
|
|
269
280
|
## [Unreleased]
|
|
281
|
+
## [0.7] - 2025-03-06
|
|
282
|
+
### Added
|
|
283
|
+
- Jalali calendar
|
|
284
|
+
- `--date-system` argument
|
|
285
|
+
### Changed
|
|
286
|
+
- `README.md` updated
|
|
270
287
|
## [0.6] - 2025-02-25
|
|
271
288
|
### Added
|
|
272
289
|
- `--calendar` argument
|
|
@@ -305,7 +322,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
305
322
|
- `TIMEZONES.md`
|
|
306
323
|
- `FACES.md`
|
|
307
324
|
|
|
308
|
-
[Unreleased]: https://github.com/sepandhaghighi/clox/compare/v0.
|
|
325
|
+
[Unreleased]: https://github.com/sepandhaghighi/clox/compare/v0.7...dev
|
|
326
|
+
[0.7]: https://github.com/sepandhaghighi/clox/compare/v0.6...v0.7
|
|
309
327
|
[0.6]: https://github.com/sepandhaghighi/clox/compare/v0.5...v0.6
|
|
310
328
|
[0.5]: https://github.com/sepandhaghighi/clox/compare/v0.4...v0.5
|
|
311
329
|
[0.4]: https://github.com/sepandhaghighi/clox/compare/v0.3...v0.4
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
clox/__init__.py,sha256=gErclFSjUDschQpngWqOBGkBKt1jwd-Ww8B9iJmlU5s,108
|
|
2
|
+
clox/__main__.py,sha256=9oJYc1WXu4ZMrjKny_2-4Cgu46-VWHuE9xOqD1iJY0E,109
|
|
3
|
+
clox/functions.py,sha256=hOXLuSMljzOMaHXJtiyxGas6XkFE9lQ51TMSC56Yq2M,8049
|
|
4
|
+
clox/jcalendar.py,sha256=yAzuyXq6h8D5aJG_He_WuPR8Xy411W_l7pl8mtPJa5U,12296
|
|
5
|
+
clox/params.py,sha256=Zd4AO6ufxpJFnXnwW3_xwzusyU4WIKS-JS29CVh2KZo,1542
|
|
6
|
+
clox-0.7.dist-info/AUTHORS.md,sha256=lmtnd18MnfgB57jdvfJbC0JHN3iARf2Ov4pY5kPGJC8,242
|
|
7
|
+
clox-0.7.dist-info/LICENSE,sha256=WoAsqqZ_lNVBGdyxjwh7YnVNXKfOB-qYVrRhrn-e-_4,1072
|
|
8
|
+
clox-0.7.dist-info/METADATA,sha256=yUonus_iE_mfLDldjTFwOSt19Fkk6Mseu6YMy9blUwk,8799
|
|
9
|
+
clox-0.7.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
10
|
+
clox-0.7.dist-info/entry_points.txt,sha256=sP4Rmoe-DxYGjlF_Tld6nghbt_u-fK8h9ZUQFmO8TJs,45
|
|
11
|
+
clox-0.7.dist-info/top_level.txt,sha256=5DxGH-4VNfYkM8vbfngObh6-jpFEoSW4M90EvDGfhSw,5
|
|
12
|
+
clox-0.7.dist-info/RECORD,,
|
clox-0.6.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
clox/__init__.py,sha256=gErclFSjUDschQpngWqOBGkBKt1jwd-Ww8B9iJmlU5s,108
|
|
2
|
-
clox/__main__.py,sha256=9oJYc1WXu4ZMrjKny_2-4Cgu46-VWHuE9xOqD1iJY0E,109
|
|
3
|
-
clox/functions.py,sha256=PS72c-LD-KzhhzyDHgEcS7yWHCDZuuUz9uCcQWwSKog,7191
|
|
4
|
-
clox/params.py,sha256=A3iNOq5NoZy9D_1lLglJK3vpG1zrk-JLrtKdK5Pc5wY,1497
|
|
5
|
-
clox-0.6.dist-info/AUTHORS.md,sha256=lmtnd18MnfgB57jdvfJbC0JHN3iARf2Ov4pY5kPGJC8,242
|
|
6
|
-
clox-0.6.dist-info/LICENSE,sha256=WoAsqqZ_lNVBGdyxjwh7YnVNXKfOB-qYVrRhrn-e-_4,1072
|
|
7
|
-
clox-0.6.dist-info/METADATA,sha256=2byZTxWOr4x3IvD0ikm5rpJgsEI-v9W_vyigOfsmWk8,8437
|
|
8
|
-
clox-0.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
9
|
-
clox-0.6.dist-info/entry_points.txt,sha256=sP4Rmoe-DxYGjlF_Tld6nghbt_u-fK8h9ZUQFmO8TJs,45
|
|
10
|
-
clox-0.6.dist-info/top_level.txt,sha256=5DxGH-4VNfYkM8vbfngObh6-jpFEoSW4M90EvDGfhSw,5
|
|
11
|
-
clox-0.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|