NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

format.py (22883B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\util\format.py
      2 from future.utils import raise_
      3 import log
      4 import blue
      5 import string
      6 import re
      7 import math
      8 import datetime
      9 import localization
     10 import eveLocalization
     11 from stdlogutils import LineWrap
     12 from eveprefs import prefs, boot
     13 SMALLDATETIME_MIN = 94432608000000000L
     14 SMALLDATETIME_MAX = 150973632000000000L
     15 __dateseptbl = string.maketrans('/-. ', '----')
     16 DECIMAL = prefs.GetValue('decimal', '.')
     17 DIGIT = prefs.GetValue('digit', ',')
     18 ROMAN_NUMERAL_MAP = (('X', 1, 10),
     19  ('IX', 2, 9),
     20  ('V', 1, 5),
     21  ('IV', 2, 4),
     22  ('I', 1, 1))
     23 romanNumeralPattern = re.compile("^                   # beginning of string\n(X{0,3})            # tens - 0-30 (0 to 3 X's),\n                    #\n(IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),\n                    #        or 5-8 (V, followed by 0 to 3 I's)\n$                   # end of string\n", re.VERBOSE)
     24 urlHttpCheck = re.compile('\\Ahttp(s)?://', re.I)
     25 
     26 def EscapeSQL(s, exactMatch = 0, min = 3):
     27     if not exactMatch:
     28         s = s.replace('%', '')
     29         s = s.replace('[', '[[]')
     30         s = s.replace('_', '[_]')
     31     return s
     32 
     33 
     34 def EscapeAdHocSQL(s):
     35     s = s.replace("'", "''")
     36     s = s.replace('%', '')
     37     s = s.replace('[', '[[]')
     38     s = s.replace('_', '[_]')
     39     return s
     40 
     41 
     42 def FmtTimeIntervalMaxParts(interval, breakAt = 'msec', maxParts = None):
     43     if interval < 10000:
     44         return localization.GetByLabel('/Carbon/UI/Common/Formatting/ShortAmountTime')
     45     breakAt2 = _GetBreakAtString(breakAt)
     46     timeInterval = localization.formatters.FormatTimeIntervalWritten(interval, showFrom='year', showTo=breakAt2, maxParts=maxParts)
     47     return timeInterval
     48 
     49 
     50 def _GetBreakAtString(breakAt):
     51     breakAt2 = breakAt
     52     if breakAt2 == 'min':
     53         breakAt2 = 'minute'
     54     elif breakAt2 == 'sec':
     55         breakAt2 = 'second'
     56     elif breakAt2 in ('msec', None):
     57         breakAt2 = 'millisecond'
     58     return breakAt2
     59 
     60 
     61 def FmtTimeInterval(interval, breakAt = 'msec', *args):
     62     return FmtTimeIntervalMaxParts(interval=interval, breakAt=breakAt)
     63 
     64 
     65 def FmtDateTimeInterval(startTime, endTime, breakAt = 'msec', highlightTime = False):
     66     interval = endTime - startTime
     67     if interval < 10000:
     68         return localization.GetByLabel('/Carbon/UI/Common/Formatting/ShortAmountTime')
     69     breakAt2 = _GetBreakAtString(breakAt)
     70     return localization.formatters.FormatDateTimeIntervalWritten(startTime, endTime, showFrom='year', showTo=breakAt2, maxParts=None, highlightTime=highlightTime)
     71 
     72 
     73 def FmtDate(date, fmt = 'll'):
     74     if date is None:
     75         return
     76     if fmt == 'nn':
     77         log.LogTraceback("Incorrect format statement used, 'nn' would result in a return value of None for all input.")
     78         fmt = 'll'
     79     if date < 0:
     80         log.LogTraceback('Negative value in FmtDate')
     81         date *= -1
     82     year1800 = const.YEAR365 * 199
     83     if fmt[1] not in ('l', 's', 'n'):
     84         log.LogTraceback('Incorrect format statement used', fmt)
     85         raise RuntimeError('InvalidArg', fmt)
     86     if date < year1800:
     87         if fmt[1] == 's':
     88             return localization.formatters.FormatTimeIntervalShortWritten(date, showFrom='day', showTo='second')
     89         else:
     90             return localization.formatters.FormatTimeIntervalWritten(date, showFrom='day', showTo='second')
     91     else:
     92         if fmt in ('ll', 'sl', 'nn', 'xs'):
     93             return localization.GetByLabel('/Carbon/UI/Common/DateTime/SimpleDateUTC', datetime=date)
     94         if fmt in ('ls', 'ss'):
     95             return localization.GetByLabel('/Carbon/UI/Common/DateTime/DateLongShort', datetime=date)
     96         if fmt in ('ln', 'sn', 'xn'):
     97             return localization.GetByLabel('/Carbon/UI/Common/DateTime/DateLongNone', datetime=date)
     98         if fmt == 'nl':
     99             return localization.GetByLabel('/Carbon/UI/Common/DateTime/Time', datetime=date)
    100         if fmt == 'ns':
    101             return localization.GetByLabel('/Carbon/UI/Common/DateTime/HoursAndMinutes', datetime=date)
    102         if fmt == 'xl':
    103             return localization.GetByLabel('/Carbon/UI/Common/DateTime/SimpleDateUTC', datetime=date)
    104         if fmt == 'el':
    105             return localization.GetByLabel('/Carbon/UI/Common/DateTime/DateExtendedLong', datetime=date)
    106         if fmt == 'es':
    107             return localization.GetByLabel('/Carbon/UI/Common/DateTime/DateExtendedShort', datetime=date)
    108         if fmt == 'en':
    109             return localization.GetByLabel('/Carbon/UI/Common/DateTime/DateExtendedNone', datetime=date)
    110         log.LogTraceback('InvalidArg', fmt)
    111         raise RuntimeError('InvalidArg', fmt)
    112 
    113 
    114 def FmtSimpleDateUTC(date):
    115     if date is None:
    116         return
    117     return localization.GetByLabel('/Carbon/UI/Common/DateTime/SimpleDateUTC', datetime=date)
    118 
    119 
    120 def FmtTime(time):
    121     hours = localization.formatters.FormatNumeric(time / const.HOUR, leadingZeroes=2)
    122     mins = localization.formatters.FormatNumeric(time % const.HOUR / const.MIN, leadingZeroes=2)
    123     secs = localization.formatters.FormatNumeric(time % const.MIN / const.SEC, leadingZeroes=2)
    124     return localization.GetByLabel('/Carbon/UI/Common/DateTimeQuantity/DateTimeShort3Elements', value1=hours, value2=mins, value3=secs)
    125 
    126 
    127 def FmtSec(time):
    128     if not time:
    129         return localization.uiutil.PrepareLocalizationSafeString('0', messageID='time')
    130     h = time / const.HOUR
    131     m = time % const.HOUR / const.MIN
    132     s = time % const.MIN / float(const.SEC)
    133     return localization.GetByLabel('/Carbon/UI/Common/FormatTime/FmtSecSpecial', hours=h, minutes=m, seconds=s)
    134 
    135 
    136 def FmtAmt(amount, fmt = 'ln', showFraction = 0, *args):
    137     if amount == None:
    138         amount = 0
    139     orgamount = amount
    140     try:
    141         amount = long(amount)
    142     except:
    143         raise RuntimeError('Amount (%s) is not an integer' % str(amount))
    144 
    145     if fmt[0] == 'l':
    146         amt = orgamount
    147         if showFraction == 0:
    148             amt = amount
    149         if amt <= const.maxLong:
    150             return localization.formatters.FormatNumeric(amt, useGrouping=True, decimalPlaces=showFraction)
    151     elif fmt[0] == 's':
    152         amt = amount
    153         val = abs(amount)
    154         labelPathDict = {('thousand', 'short'): '/Carbon/UI/Common/Formatting/FmtThousandShort',
    155          ('thousand', 'long'): '/Carbon/UI/Common/Formatting/FmtThousandLong',
    156          ('million', 'short'): '/Carbon/UI/Common/Formatting/FmtMillionShort',
    157          ('million', 'long'): '/Carbon/UI/Common/Formatting/FmtMillionLong',
    158          ('billion', 'short'): '/Carbon/UI/Common/Formatting/FmtBillionShort',
    159          ('billion', 'long'): '/Carbon/UI/Common/Formatting/FmtBillionLong',
    160          ('trillion', 'short'): '/Carbon/UI/Common/Formatting/FmtTrillionShort',
    161          ('trillion', 'long'): '/Carbon/UI/Common/Formatting/FmtTrillionLong'}
    162         if fmt[1] == 'l':
    163             labelLength = 'long'
    164         else:
    165             labelLength = 'short'
    166         if val >= 100000000000000.0:
    167             raise UserError('WhatKindOfAmountIsThis', {'amount': amount})
    168         if val < 10000.0:
    169             return localization.formatters.FormatNumeric(amt, useGrouping=True)
    170         if val < 100000.0:
    171             amt = float(amt) / long(1000.0)
    172             labelPath = labelPathDict.get(('thousand', labelLength))
    173         elif val < 100000000.0:
    174             amt = float(amt) / long(1000000.0)
    175             labelPath = labelPathDict.get(('million', labelLength))
    176         elif val < 100000000000.0:
    177             amt = float(amt) / long(1000000000.0)
    178             labelPath = labelPathDict.get(('billion', labelLength))
    179         elif val < 100000000000000.0:
    180             amt = float(amt) / long(1000000000000.0)
    181             labelPath = labelPathDict.get(('trillion', labelLength))
    182         return localization.GetByLabel(labelPath, amount=amt)
    183     return localization.uiutil.PrepareLocalizationSafeString(orgamount, messageID='amount')
    184 
    185 
    186 def FmtAmtCapped(amount, fmt = 'sn'):
    187     formattedAmount = FmtAmt(amount, fmt)
    188     return localization.GetByLabel('/Carbon/UI/Common/Formatting/FmtAmountCapped', amount=formattedAmount)
    189 
    190 
    191 def FmtDist(dist, maxdemicals = 2, signed = False):
    192     if signed and dist < 0.0:
    193         dist = abs(dist)
    194     dist = max(0, dist)
    195     if dist < 10000.0:
    196         if dist == 0 or dist >= 1.0:
    197             dist = int(round(dist))
    198             maxdemicals = None
    199         fmtUrl = '/Carbon/UI/Common/FormatDistance/fmtDistInMeters'
    200     elif dist < 10000000000.0:
    201         dist = long(round(dist / 1000.0))
    202         maxdemicals = None
    203         fmtUrl = '/Carbon/UI/Common/FormatDistance/fmtDistInKiloMeters'
    204     else:
    205         dist = round(dist / const.AU, maxdemicals)
    206         fmtUrl = '/Carbon/UI/Common/FormatDistance/fmtDistInAU'
    207     if maxdemicals == 0:
    208         maxdemicals = None
    209         dist = int(dist)
    210     distStr = localization.formatters.FormatNumeric(dist, useGrouping=True, decimalPlaces=maxdemicals)
    211     return localization.GetByLabel(fmtUrl, distance=distStr)
    212 
    213 
    214 def RoundDistance(dist, maxDecimals = 2):
    215     if dist < 0.0:
    216         dist = abs(dist)
    217     if dist < 10000.0:
    218         if dist == 0 or dist >= 1.0:
    219             return int(round(dist))
    220     else:
    221         if dist < 10000000000.0:
    222             return long(round(dist / 1000.0))
    223         return round(dist / const.AU, maxDecimals)
    224 
    225 
    226 def FmtVec(vec, maxdecimals = 3):
    227     return '[%s, %s, %s]' % (FmtDist(vec[0], maxdecimals, signed=True), FmtDist(vec[1], maxdecimals, signed=True), FmtDist(vec[2], maxdecimals, signed=True))
    228 
    229 
    230 def FmtYesNo(isYes):
    231     if isYes:
    232         return localization.GetByLabel('UI/Common/Yes')
    233     else:
    234         return localization.GetByLabel('UI/Common/No')
    235 
    236 
    237 def ParseDate(date):
    238     if date is None or date == '':
    239         return
    240     if type(date) == unicode:
    241         date = str(date)
    242     try:
    243         date = string.translate(date.split(' ')[0], __dateseptbl)
    244         dp = date.split('-', 2)
    245         return blue.os.GetTimeFromParts(int(dp[0]), int(dp[1]), int(dp[2]), 0, 0, 0, 0)
    246     except:
    247         raise UserError('InvalidDate', {'date': date})
    248 
    249 
    250 def ParseTime(time, isInterval = False):
    251     if time is None or time == '':
    252         return
    253     try:
    254         tp = time.split(':', 2)
    255         time = int(tp[0]) * const.HOUR + int(tp[1]) * const.MIN
    256         if len(tp) == 3:
    257             time = time + int(tp[2]) * const.SEC
    258         if not isInterval and boot.region == 'optic':
    259             time -= eveLocalization.GetTimeDelta() * const.SEC
    260             if time < 0:
    261                 time += 24 * const.HOUR
    262         return time
    263     except:
    264         raise UserError('InvalidTime', {'time': time})
    265 
    266 
    267 def ParseDateTime(dateTime):
    268     if dateTime is None or dateTime == '':
    269         return
    270     if ' ' in dateTime:
    271         d, t = dateTime.split(' ')
    272         dateTime = ParseDate(d)
    273         dateTime += ParseTime(t)
    274     else:
    275         dateTime = ParseDate(dateTime)
    276     return dateTime
    277 
    278 
    279 def ParseTimeInterval(time):
    280     return ParseTime(time, True)
    281 
    282 
    283 def GetTimeParts(datetime, utc = False):
    284     if not utc and datetime % const.DAY and boot.region == 'optic':
    285         datetime += eveLocalization.GetTimeDelta() * const.SEC
    286     return blue.os.GetTimeParts(datetime)
    287 
    288 
    289 months = [31,
    290  59,
    291  90,
    292  120,
    293  151,
    294  181,
    295  212,
    296  243,
    297  273,
    298  304,
    299  334,
    300  365]
    301 monthsl = [31,
    302  60,
    303  91,
    304  121,
    305  152,
    306  182,
    307  213,
    308  244,
    309  274,
    310  305,
    311  335,
    312  366]
    313 
    314 def isleap(year):
    315     return not year % 4
    316 
    317 
    318 def dateConvert(tmp):
    319     if isleap(tmp[const.TP_YEAR]):
    320         m = monthsl
    321     else:
    322         m = months
    323     return (tmp[const.TP_YEAR],
    324      tmp[const.TP_MONTH],
    325      tmp[const.TP_DAY],
    326      tmp[const.TP_HOUR],
    327      tmp[const.TP_MIN],
    328      tmp[const.TP_SEC],
    329      tmp[const.TP_DAY_OF_WEEK],
    330      m[tmp[const.TP_MONTH] - 1] + tmp[const.TP_DAY],
    331      0)
    332 
    333 
    334 def ConvertDate(blueTime):
    335     import time
    336     return time.mktime(dateConvert(blue.os.GetTimeParts(blueTime)))
    337 
    338 
    339 def BlueToDate(time):
    340     if time is not None:
    341         parts = blue.os.GetTimeParts(time)
    342         return datetime.datetime(*(parts[:2] + parts[3:]))
    343 
    344 
    345 def DateToBlue(time):
    346     if time is not None:
    347         return blue.os.GetTimeFromParts(time.year, time.month, time.day, time.hour, time.minute, time.second, time.microsecond / 1000)
    348 
    349 
    350 def FmtCdkey(cdkey):
    351     if not cdkey:
    352         return ''
    353     return '%s-%s-%s-%s-%s-%s-%s' % (cdkey[0:5],
    354      cdkey[5:10],
    355      cdkey[10:15],
    356      cdkey[15:20],
    357      cdkey[20:25],
    358      cdkey[25:30],
    359      cdkey[30:35])
    360 
    361 
    362 def CaseFold(s):
    363     s2 = s.upper().lower()
    364     if s2 != s:
    365         return CaseFold(s2)
    366     return s2
    367 
    368 
    369 def CaseFoldCompare(l, r):
    370     l2 = l.upper().lower()
    371     r2 = r.upper().lower()
    372     if l2 != l or r2 != r:
    373         return CaseFoldCompare(l2, r2)
    374     return cmp(l, r)
    375 
    376 
    377 def CaseFoldEquals(l, r):
    378     return CaseFoldCompare(l, r) == 0
    379 
    380 
    381 class PasswordString(unicode):
    382 
    383     def __str__(self):
    384         return '*****'
    385 
    386     def __repr__(self):
    387         return '*****'
    388 
    389 
    390 def GetKeyAndNormalize(string):
    391     key = string
    392     norm = string
    393     for c in key:
    394         if c.isspace():
    395             key = key.replace(c, '')
    396             while True:
    397                 prev = norm
    398                 norm = norm.replace(c + c, c)
    399                 if prev == norm:
    400                     break
    401                 blue.pyos.BeNice()
    402 
    403     key = key.split('\\')[-1]
    404     return (CaseFold(key), norm)
    405 
    406 
    407 def SecsFromBlueTimeDelta(t):
    408     return t / const.SEC
    409 
    410 
    411 def HoursMinsSecsFromSecs(s):
    412     s = max(0, s)
    413     secs = int(s % 60)
    414     mins = int(s / 60 % 60)
    415     hours = int(s / 3600)
    416     return (hours, mins, secs)
    417 
    418 
    419 def FormatTimeAgo(theTime):
    420     delta = blue.os.GetWallclockTime() - theTime
    421     hours, minutes, seconds = HoursMinsSecsFromSecs(SecsFromBlueTimeDelta(delta))
    422     if hours + minutes + seconds <= 0:
    423         howLongAgo = localization.GetByLabel('/Carbon/UI/Common/FormatTime/FmtTimeAgoRightNow')
    424     else:
    425         howLongAgo = localization.GetByLabel('/Carbon/UI/Common/FormatTime/FmtTimeAgoDays', time=delta)
    426     return howLongAgo
    427 
    428 
    429 def ParseSmallDate(date):
    430     parsedDate = ParseDate(date)
    431     if parsedDate > SMALLDATETIME_MIN and parsedDate < SMALLDATETIME_MAX:
    432         return parsedDate
    433     raise TypeError('Date is not a legal SmallDateTime value.')
    434 
    435 
    436 def RomanToInt(roman):
    437     result = 0
    438     index = 0
    439     if not romanNumeralPattern.search(roman):
    440         raise_(RuntimeError, 'Invalid Roman numeral: %s' % roman)
    441     for numeral, length, integer in ROMAN_NUMERAL_MAP:
    442         while roman[index:index + length] == numeral:
    443             result += integer
    444             index += length
    445 
    446     return result
    447 
    448 
    449 def IntToRoman(n):
    450     if not 0 < n < 40:
    451         raise RuntimeError('number out of range (must be 1..4999)')
    452     if int(n) != n:
    453         raise RuntimeError('non-integers can not be converted')
    454     result = ''
    455     for numeral, length, integer in ROMAN_NUMERAL_MAP:
    456         while n >= integer:
    457             result += numeral
    458             n -= integer
    459 
    460     return localization.uiutil.PrepareLocalizationSafeString(result, messageID='intToRoman')
    461 
    462 
    463 def GetYearMonthFromTime(blueTime):
    464     t = blue.os.GetTimeParts(blueTime)
    465     return (t[0], t[1])
    466 
    467 
    468 def FormatUrl(url):
    469     url = url.strip()
    470     if len(url) and not urlHttpCheck.match(url):
    471         return 'http://%s' % url
    472     return url
    473 
    474 
    475 def FmtDateEng(date, fmt = 'll', localizeTime = True):
    476     if date is None:
    477         return
    478     if fmt == 'nn':
    479         log.LogTraceback("Incorrect format statement used, 'nn' would result in a return value of None for all input.")
    480         fmt = 'll'
    481     if date < 0:
    482         date *= -1
    483         neg = '-'
    484     else:
    485         neg = ''
    486     year1800 = const.YEAR365 * 199
    487     if localizeTime and date >= year1800 and date % const.DAY and boot.region == 'optic':
    488         date += 8 * const.HOUR
    489     year, month, wd, day, hour, min, sec, ms = blue.os.GetTimeParts(date)
    490     sd = '%d.%.2d.%.2d' % (year, month, day)
    491     ld = sd
    492     lt = '%.2d:%.2d:%.2d' % (hour, min, sec)
    493     if fmt[0] == 'x':
    494         lt += ':%3d' % ms
    495     ed = '%d-%.2d-%.2d' % (year, month, day)
    496     st = lt[:-3]
    497     if fmt[1] == 'l':
    498         hrs = lt
    499     elif fmt[1] == 's':
    500         hrs = st
    501     elif fmt[1] == 'n':
    502         hrs = None
    503     else:
    504         raise RuntimeError('InvalidArg', fmt)
    505     if date % const.DAY == 0:
    506         hrs = None
    507     if date < year1800:
    508         datefmt = None
    509         days = date / const.DAY
    510         s = date % const.MIN / const.SEC
    511         m = date % const.HOUR / const.MIN
    512         h = date % const.DAY / const.HOUR
    513         hrs = ''
    514         if fmt[1] == 's':
    515             if days:
    516                 hrs = '%d%s' % (days, 'D')
    517             if h:
    518                 hrs = hrs + ' %d%s' % (h, 'H')
    519             if m:
    520                 hrs = hrs + ' %d%s' % (m, 'M')
    521             if s:
    522                 hrs = hrs + ' %d%s' % (s, 'S')
    523         else:
    524             if days:
    525                 hrs = '%d %s' % (days, ['day', 'days'][days != 1])
    526             if h:
    527                 hrs = hrs + ' %d %s' % (h, ['hour', 'hours'][h != 1])
    528             if m:
    529                 hrs = hrs + ' %d %s' % (m, ['minute', 'minutes'][m != 1])
    530             if s or hrs == '':
    531                 hrs = hrs + ' %d %s' % (s, ['second', 'seconds'][s != 1])
    532     elif fmt[0] == 'l' or fmt[0] == 'x':
    533         datefmt = ld
    534     elif fmt[0] == 's':
    535         datefmt = sd
    536     elif fmt[0] == 'n':
    537         datefmt = None
    538     elif fmt[0] == 'e':
    539         datefmt = ed
    540     else:
    541         raise RuntimeError('InvalidArg', fmt)
    542     if datefmt is None and hrs is None:
    543         return
    544     elif datefmt is not None and hrs is None:
    545         return neg + datefmt
    546     elif datefmt is None and hrs is not None:
    547         return neg + hrs.strip()
    548     elif fmt[0] == 'e':
    549         return '%s%sT%s.000' % (neg, datefmt, hrs)
    550     else:
    551         return '%s%s %s' % (neg, datefmt, hrs)
    552 
    553 
    554 def FmtTimeIntervalEng(interval, breakAt = None, *args, **kwargs):
    555     if interval < 10000:
    556         return 'A short amount of time'
    557     year, month, wd, day, hour, min, sec, ms = blue.os.GetTimeParts(interval)
    558     year -= 1601
    559     month -= 1
    560     day -= 1
    561     items = []
    562     while 1:
    563         if year:
    564             items.append(str(year) + ' ' + ['year', 'years'][year > 1])
    565         if breakAt == 'year':
    566             break
    567         if month:
    568             items.append(str(month) + ' ' + ['month', 'months'][month > 1])
    569         if breakAt == 'month':
    570             break
    571         if day:
    572             items.append(str(day) + ' ' + ['day', 'days'][day > 1])
    573         if breakAt == 'day':
    574             break
    575         if hour:
    576             items.append(str(hour) + ' ' + ['hour', 'hours'][hour > 1])
    577         if breakAt == 'hour':
    578             break
    579         if min:
    580             items.append(str(min) + ' ' + ['minute', 'minutes'][min > 1])
    581         if breakAt == 'min':
    582             break
    583         if sec:
    584             items.append(str(sec) + ' ' + ['second', 'seconds'][sec > 1])
    585         if breakAt == 'sec':
    586             break
    587         if ms:
    588             items.append(str(ms) + ' ' + ['millisecond', 'milliseconds'][ms > 1])
    589         break
    590 
    591     if items:
    592         if len(items) == 1:
    593             return items[0]
    594         else:
    595             lastItem = items.pop()
    596             return ', '.join(items) + ' ' + 'and' + ' ' + lastItem
    597     else:
    598         if breakAt == 'sec':
    599             return 'Less than a second'
    600         if breakAt == 'min':
    601             return 'Less than a minute'
    602         return {'DAY': 'less than a day',
    603          'HOUR': 'less than an hour',
    604          'MILLISECOND': 'less than a millisecond',
    605          'MINUTE': 'less than a minute',
    606          'MONTH': 'less than a month',
    607          'SECOND': 'less than a second',
    608          'YEAR': 'less than a year'}.get(breakAt.upper(), 'less than a ' + breakAt)
    609 
    610 
    611 def FmtTimeEng(time):
    612     return '%.2d:%.2d:%.2d' % (time / const.HOUR, time % const.HOUR / const.MIN, time % const.MIN / const.SEC)
    613 
    614 
    615 def FmtAmtEng(amount, fmt = 'ln', showFraction = 0, fillWithZero = 0):
    616     if amount == None:
    617         amount = 0
    618     orgamount = amount
    619     try:
    620         amount = long(amount)
    621     except:
    622         raise RuntimeError('AmountMustBeInteger', amount)
    623 
    624     minus = ['', '-'][float(orgamount) < 0.0]
    625     fraction = ''
    626     ret = ''
    627     fractionNumber = None
    628     if fmt[0] == 'l':
    629         if showFraction:
    630             fraction = abs(math.fmod(orgamount, 1.0))
    631             fraction = round(fraction, showFraction)
    632             if fraction >= 1.0:
    633                 amount += [-1, 1][amount >= 0.0]
    634                 fraction = 0.0
    635             fraction = str(fraction)[2:]
    636             if fillWithZero:
    637                 while len(fraction) < showFraction:
    638                     fraction += '0'
    639 
    640             fractionNumber = float('%s.%s' % (amount, fraction))
    641             fraction = DECIMAL + str(fraction)
    642         digit = ''
    643         amt = '%d' % abs(amount)
    644         for i in xrange(len(amt) % 3, len(amt) + 3, 3):
    645             if i < 3:
    646                 ret = ret + amt[:i]
    647             else:
    648                 ret = ret + digit + amt[i - 3:i]
    649             if i != 0:
    650                 digit = DIGIT
    651 
    652     elif fmt[0] == 's':
    653         val = abs(amount)
    654         fractionNumber = val
    655         isOne = str(val)[0] == '1'
    656         if val < 10000.0:
    657             ret = str(val)
    658         elif val < 100000.0:
    659             if fmt[1] == 'l':
    660                 unitString = ['thousands', 'thousand'][isOne]
    661             else:
    662                 unitString = 'K'
    663             ret = '%s%s' % (TruncateAmt(val, long(1000.0)), unitString)
    664         elif val < 100000000.0:
    665             if fmt[1] == 'l':
    666                 unitString = ['millions', 'million'][isOne]
    667             else:
    668                 unitString = 'M'
    669             ret = '%s%s' % (TruncateAmt(val, long(1000000.0)), unitString)
    670         elif val < 100000000000.0:
    671             if fmt[1] == 'l':
    672                 unitString = ['billions', 'billion'][isOne]
    673             else:
    674                 unitString = 'B'
    675             ret = '%s%s' % (TruncateAmt(val, long(1000000000.0)), unitString)
    676         elif val < 100000000000000.0:
    677             if fmt[1] == 'l':
    678                 unitString = ['trillions', 'trillion'][isOne]
    679             else:
    680                 unitString = 'T'
    681             ret = '%s%s' % (TruncateAmt(val, long(1000000000000.0)), unitString)
    682         else:
    683             raise UserError('WhatKindOfAmountIsThis', {'amount': amount})
    684     else:
    685         ret = '%d' % abs(amount)
    686     if fractionNumber == 0:
    687         minus = ''
    688     return minus + ret + fraction
    689 
    690 
    691 def TruncateAmt(val, unit):
    692     rest = val % unit / (unit / 100)
    693     ret = str(val / unit)
    694     if rest > 0:
    695         ret = ret + '%s%02d' % (DECIMAL, rest)
    696         if ret[-1:] == '0':
    697             ret = ret[:-1]
    698     return ret
    699 
    700 
    701 def FmtSecEng(time):
    702     if not time:
    703         return '0'
    704     h = time / const.HOUR
    705     m = time % const.HOUR / const.MIN
    706     s = time % const.MIN / float(const.SEC)
    707     return "%.2d:%.2d'%06.3f" % (h, m, s)
    708 
    709 
    710 def FormatVulnerabilityIntervalESP(vulnerabilityInterval):
    711     if vulnerabilityInterval is None:
    712         return 'None'
    713     return 'Start: %s<br>End: %s<br>Level:%s' % (FmtDate(vulnerabilityInterval.startTime), FmtDate(vulnerabilityInterval.endTime), vulnerabilityInterval.occupancyLevel)