Package pytils :: Module dt
[hide private]
[frames] | no frames]

Source Code for Module pytils.dt

  1  # -*- coding: utf-8 -*- 
  2  # -*- test-case-name: pytils.test.test_dt -*- 
  3  # License: GNU GPL2 
  4  # Author: Pythy <the.pythy@gmail.com> 
  5  """ 
  6  Russian dates without locales 
  7  """ 
  8   
  9  __id__ = __revision__ = "$Id: dt.py 29 2006-10-21 08:28:27Z the.pythy $" 
 10  __url__ = "$URL: https://pythy.googlecode.com/svn/trunk/pytils/pytils/dt.py $" 
 11   
 12  import datetime 
 13   
 14  from pytils import numeral, utils 
 15   
 16  DAY_ALTERNATIVES = { 
 17      1: (u"вчера", u"завтра"), 
 18      2: (u"позавчера", u"послезавтра") 
 19      }  #: Day alternatives (i.e. one day ago -> yesterday)  
 20   
 21  DAY_VARIANTS = ( 
 22      u"день", 
 23      u"дня", 
 24      u"дней", 
 25      )  #: Forms (1, 2, 5) for noun 'day' 
 26   
 27  HOUR_VARIANTS = ( 
 28      u"час", 
 29      u"часа", 
 30      u"часов", 
 31      )  #: Forms (1, 2, 5) for noun 'hour' 
 32   
 33  MINUTE_VARIANTS = ( 
 34      u"минуту", 
 35      u"минуты", 
 36      u"минут", 
 37      )  #: Forms (1, 2, 5) for noun 'minute' 
 38   
 39  PREFIX_IN = u"через"  #: Prefix 'in' (i.e. B{in} three hours) 
 40  SUFFIX_AGO = u"назад"  #: Prefix 'ago' (i.e. three hours B{ago}) 
 41   
 42  MONTH_NAMES = ( 
 43      (u"янв", u"январь", u"января"), 
 44      (u"фев", u"февраль", u"февраля"), 
 45      (u"мар", u"март", u"марта"), 
 46      (u"апр", u"апрель", u"апреля"), 
 47      (u"май", u"май", u"мая"), 
 48      (u"июн", u"июнь", u"июня"), 
 49      (u"июл", u"июль", u"июля"), 
 50      (u"авг", u"август", u"августа"), 
 51      (u"сен", u"сентябрь", u"сентября"), 
 52      (u"окт", u"октябрь", u"октября"), 
 53      (u"ноя", u"ноябрь", u"ноября"), 
 54      (u"дек", u"декабрь", u"декабря"), 
 55      )  #: Month names (abbreviated, full, inflected) 
 56   
 57  DAY_NAMES = ( 
 58      (u"пн", u"понедельник", u"понедельник"), 
 59      (u"вт", u"вторник", u"вторник"), 
 60      (u"ср", u"среда", u"среду"), 
 61      (u"чт", u"четверг", u"четверг"), 
 62      (u"пт", u"пятница", u"пятницу"), 
 63      (u"сб", u"суббота", u"субботу"), 
 64      (u"вск", u"воскресенье", u"субботу"), 
 65      )  #: Day names (abbreviated, full, inflected) 
 66   
 67   
68 -def distance_of_time_in_words(from_time, accuracy=1, to_time=None):
69 """ 70 Represents distance of time in words 71 72 @param from_time: source time (in seconds from epoch) 73 @type from_time: C{int}, C{float} or C{datetime.datetime} 74 75 @param accuracy: level of accuracy (1..3), default=1 76 @type accuracy: C{int} 77 78 @param to_time: target time (in seconds from epoch), 79 default=None translates to current time 80 @type to_time: C{int}, C{float} or C{datetime.datetime} 81 82 @return: distance of time in words 83 @rtype: unicode 84 85 @raise TypeError: input parameters' check failed 86 @raise ValueError: accuracy is lesser or equal zero 87 """ 88 current = False 89 90 if to_time is None: 91 current = True 92 to_time = datetime.datetime.now() 93 94 utils.check_type('from_time', (int, float, datetime.datetime)) 95 utils.check_type('to_time', (int, float, datetime.datetime)) 96 utils.check_type('accuracy', int) 97 utils.check_positive('accuracy', strict=True) 98 99 if not isinstance(from_time, datetime.datetime): 100 from_time = datetime.datetime.fromtimestamp(from_time) 101 102 if not isinstance(to_time, datetime.datetime): 103 to_time = datetime.datetime.fromtimestamp(to_time) 104 105 dt_delta = to_time - from_time 106 difference = dt_delta.days*86400 + dt_delta.seconds 107 108 seconds_orig = int(abs(difference)) 109 minutes_orig = int(abs(difference)/60.0) 110 hours_orig = int(abs(difference)/3600.0) 111 days_orig = int(abs(difference)/86400.0) 112 in_future = from_time > to_time 113 114 words = [] 115 values = [] 116 alternatives = [] 117 118 days = days_orig 119 hours = hours_orig - days_orig*24 120 121 words.append(u"%d %s" % (days, numeral.choose_plural(days, DAY_VARIANTS))) 122 values.append(days) 123 124 words.append(u"%d %s" % \ 125 (hours, numeral.choose_plural(hours, HOUR_VARIANTS))) 126 values.append(hours) 127 128 hours == 1 and current and alternatives.append(u"час") 129 130 minutes = minutes_orig - hours_orig*60 131 132 words.append(u"%d %s" % (minutes, 133 numeral.choose_plural(minutes, MINUTE_VARIANTS))) 134 values.append(minutes) 135 136 minutes == 1 and current and alternatives.append(u"минуту") 137 138 real_words = words 139 # убираем из values и words конечные нули 140 while values and not values[-1]: 141 values.pop() 142 words.pop() 143 # убираем из values и words начальные нули 144 while values and not values[0]: 145 values.pop(0) 146 words.pop(0) 147 limit = min(accuracy, len(words)) 148 real_words = words[:limit] 149 real_values = values[:limit] 150 # снова убираем конечные нули 151 while real_values and not real_values[-1]: 152 real_values.pop() 153 real_words.pop() 154 limit -= 1 155 156 real_str = u" ".join(real_words) 157 158 # альтернативные варианты нужны только если в real_words одно значение 159 # и, вдобавок, если используется текущее время 160 alter_str = limit == 1 and current and \ 161 alternatives and alternatives[0] 162 _result_str = alter_str or real_str 163 result_str = in_future and u"%s %s" % (PREFIX_IN, _result_str) \ 164 or u"%s %s" % (_result_str, SUFFIX_AGO) 165 166 # если же прошло менее минуты, то real_words -- пустой, и поэтому 167 # нужно брать alternatives[0], а не result_str 168 zero_str = minutes == 0 and not real_words and \ 169 (in_future and u"менее чем через минуту" \ 170 or u"менее минуты назад") 171 172 # нужно использовать вчера/позавчера/завтра/послезавтра 173 # если days 1..2 и в real_words одно значение 174 day_alternatives = DAY_ALTERNATIVES.get(days, False) 175 alternate_day = day_alternatives and current and limit == 1 and \ 176 ((in_future and day_alternatives[1]) \ 177 or day_alternatives[0]) 178 179 180 final_str = not real_words and zero_str or alternate_day or result_str 181 182 return final_str
183 184
185 -def ru_strftime(format=u"%d.%m.%Y", date=None, inflected=False, inflected_day=False):
186 """ 187 Russian strftime without locale 188 189 @param format: strftime format, default=u'%d.%m.%Y' 190 @type format: C{unicode} 191 192 @param date: date value, default=None translates to today 193 @type date: C{datetime.date} or C{datetime.datetime} 194 195 @return: strftime string 196 @rtype: unicode 197 198 @raise TypeError: input parameters' check failed 199 """ 200 if date is None: 201 date = datetime.datetime.today() 202 utils.check_type('date', (datetime.date, datetime.datetime)) 203 utils.check_type('format', unicode) 204 205 midx = inflected and 2 or 1 206 didx = inflected_day and 2 or 1 207 208 format = format.replace(u'%a', DAY_NAMES[date.weekday()][0]) 209 format = format.replace(u'%A', DAY_NAMES[date.weekday()][didx]) 210 format = format.replace(u'%b', MONTH_NAMES[date.month-1][0]) 211 format = format.replace(u'%B', MONTH_NAMES[date.month-1][midx]) 212 213 # strftime must be str, so encode it to utf8: 214 s_format = format.encode("utf-8") 215 s_res = date.strftime(s_format) 216 # and back to unicode 217 u_res = s_res.decode("utf-8") 218 219 return u_res
220