| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- # -*- coding: utf-8 -*-
- # -*- test-case-name: pytils.test.test_dt -*-
- """
- Russian dates without locales
- """
- import datetime
- from pytils import numeral
- from pytils.utils import check_positive
- DAY_ALTERNATIVES = {
- 1: ("вчера", "завтра"),
- 2: ("позавчера", "послезавтра")
- } #: Day alternatives (i.e. one day ago -> yesterday)
- DAY_VARIANTS = (
- "день",
- "дня",
- "дней",
- ) #: Forms (1, 2, 5) for noun 'day'
- HOUR_VARIANTS = (
- "час",
- "часа",
- "часов",
- ) #: Forms (1, 2, 5) for noun 'hour'
- MINUTE_VARIANTS = (
- "минуту",
- "минуты",
- "минут",
- ) #: Forms (1, 2, 5) for noun 'minute'
- PREFIX_IN = "через" #: Prefix 'in' (i.e. B{in} three hours)
- SUFFIX_AGO = "назад" #: Prefix 'ago' (i.e. three hours B{ago})
- MONTH_NAMES = (
- ("янв", "январь", "января"),
- ("фев", "февраль", "февраля"),
- ("мар", "март", "марта"),
- ("апр", "апрель", "апреля"),
- ("май", "май", "мая"),
- ("июн", "июнь", "июня"),
- ("июл", "июль", "июля"),
- ("авг", "август", "августа"),
- ("сен", "сентябрь", "сентября"),
- ("окт", "октябрь", "октября"),
- ("ноя", "ноябрь", "ноября"),
- ("дек", "декабрь", "декабря"),
- ) #: Month names (abbreviated, full, inflected)
- DAY_NAMES = (
- ("пн", "понедельник", "понедельник", "в\xa0"),
- ("вт", "вторник", "вторник", "во\xa0"),
- ("ср", "среда", "среду", "в\xa0"),
- ("чт", "четверг", "четверг", "в\xa0"),
- ("пт", "пятница", "пятницу", "в\xa0"),
- ("сб", "суббота", "субботу", "в\xa0"),
- ("вск", "воскресенье", "воскресенье", "в\xa0")
- ) #: Day names (abbreviated, full, inflected, preposition)
- def distance_of_time_in_words(from_time, accuracy=1, to_time=None):
- """
- Represents distance of time in words
- @param from_time: source time (in seconds from epoch)
- @type from_time: C{int}, C{float} or C{datetime.datetime}
- @param accuracy: level of accuracy (1..3), default=1
- @type accuracy: C{int}
- @param to_time: target time (in seconds from epoch),
- default=None translates to current time
- @type to_time: C{int}, C{float} or C{datetime.datetime}
- @return: distance of time in words
- @rtype: C{str}
- @raise ValueError: accuracy is lesser or equal zero
- """
- current = False
- if to_time is None:
- current = True
- to_time = datetime.datetime.now()
- check_positive(accuracy, strict=True)
- if not isinstance(from_time, datetime.datetime):
- from_time = datetime.datetime.fromtimestamp(from_time)
- if not isinstance(to_time, datetime.datetime):
- to_time = datetime.datetime.fromtimestamp(to_time)
- if from_time.tzinfo and not to_time.tzinfo:
- to_time = to_time.replace(tzinfo=from_time.tzinfo)
- dt_delta = to_time - from_time
- difference = dt_delta.days*86400 + dt_delta.seconds
- minutes_orig = int(abs(difference)/60.0)
- hours_orig = int(abs(difference)/3600.0)
- days_orig = int(abs(difference)/86400.0)
- in_future = from_time > to_time
- words = []
- values = []
- alternatives = []
- days = days_orig
- hours = hours_orig - days_orig*24
- words.append("%d %s" % (days, numeral.choose_plural(days, DAY_VARIANTS)))
- values.append(days)
- words.append("%d %s" %
- (hours, numeral.choose_plural(hours, HOUR_VARIANTS)))
- values.append(hours)
- days == 0 and hours == 1 and current and alternatives.append("час")
- minutes = minutes_orig - hours_orig*60
- words.append("%d %s" % (minutes,
- numeral.choose_plural(minutes, MINUTE_VARIANTS)))
- values.append(minutes)
- days == 0 and hours == 0 and minutes == 1 and current and \
- alternatives.append("минуту")
- # убираем из values и words конечные нули
- while values and not values[-1]:
- values.pop()
- words.pop()
- # убираем из values и words начальные нули
- while values and not values[0]:
- values.pop(0)
- words.pop(0)
- limit = min(accuracy, len(words))
- real_words = words[:limit]
- real_values = values[:limit]
- # снова убираем конечные нули
- while real_values and not real_values[-1]:
- real_values.pop()
- real_words.pop()
- limit -= 1
- real_str = u" ".join(real_words)
- # альтернативные варианты нужны только если в real_words одно значение
- # и, вдобавок, если используется текущее время
- alter_str = limit == 1 and current and alternatives and \
- alternatives[0]
- _result_str = alter_str or real_str
- result_str = in_future and "%s %s" % (PREFIX_IN, _result_str) \
- or "%s %s" % (_result_str, SUFFIX_AGO)
- # если же прошло менее минуты, то real_words -- пустой, и поэтому
- # нужно брать alternatives[0], а не result_str
- zero_str = minutes == 0 and not real_words and \
- (in_future and "менее чем через минуту"
- or "менее минуты назад")
- # нужно использовать вчера/позавчера/завтра/послезавтра
- # если days 1..2 и в real_words одно значение
- day_alternatives = DAY_ALTERNATIVES.get(days, False)
- alternate_day = day_alternatives and current and limit == 1 and \
- ((in_future and day_alternatives[1])
- or day_alternatives[0])
- final_str = not real_words and zero_str or alternate_day or result_str
- return final_str
- def ru_strftime(format="%d.%m.%Y", date=None, inflected=False,
- inflected_day=False, preposition=False):
- """
- Russian strftime without locale
- @param format: strftime format, default='%d.%m.%Y'
- @type format: C{str}
- @param date: date value, default=None translates to today
- @type date: C{datetime.date} or C{datetime.datetime}
- @param inflected: is month inflected, default False
- @type inflected: C{bool}
- @param inflected_day: is day inflected, default False
- @type inflected: C{bool}
- @param preposition: is preposition used, default False
- preposition=True automatically implies inflected_day=True
- @type preposition: C{bool}
- @return: strftime string
- @rtype: C{str}
- """
- if date is None:
- date = datetime.datetime.today()
- weekday = date.weekday()
- prepos = preposition and DAY_NAMES[weekday][3] or u""
- month_idx = inflected and 2 or 1
- day_idx = (inflected_day or preposition) and 2 or 1
- # for russian typography standard,
- # 1 April 2007, but 01.04.2007
- if '%b' in format or '%B' in format:
- format = format.replace('%d', str(date.day))
- format = format.replace('%a', prepos+DAY_NAMES[weekday][0])
- format = format.replace('%A', prepos+DAY_NAMES[weekday][day_idx])
- format = format.replace('%b', MONTH_NAMES[date.month-1][0])
- format = format.replace('%B', MONTH_NAMES[date.month-1][month_idx])
- u_res = date.strftime(format)
- return u_res
|