日期格式化字符串:DATE_FORMAT = "%Y-%m-%d"
日期时间格式字符串:DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
日期时间格式字符串(包含毫秒):DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
OpenERP对象中字段赋值为当前日期(字符串):fields.date.context_today,fields.date.context_today(self, cr, uid, context=context),fields.date.today()
OpenERP对象中字段赋值为当前时间(字符串):fields.datetime.now(),fields.datetime.context_timestamp(cr, uid, datetime.now(), context=context)
OpenERP官方建议 date/datetime 的默认值的写法是:fields.date.context_today,fields.datetime.now()
字符串转换为日期时间:datetime.datetime.strptime(sale.date, DATE_FORMAT)
日期时间转换为字符串:datetime.datetime.strftime(datetime.date.today(), DATE_FORMAT)
python中获取当前日期:datetime.date.today()
python中获取当前时间:datetime.datetime.now()
OpenERP fields 单元中对 date/datetime 类中方法定义如下所示:
class date(_column): _type = 'date' @staticmethod def today(*args): """ Returns the current date in a format fit for being a default value to a ``date`` field. This method should be provided as is to the _defaults dict, it should not be called. """ return DT.date.today().strftime( tools.DEFAULT_SERVER_DATE_FORMAT) @staticmethod def context_today(model, cr, uid, context=None, timestamp=None): """Returns the current date as seen in the client's timezone in a format fit for date fields. This method may be passed as value to initialize _defaults. :param Model model: model (osv) for which the date value is being computed - automatically passed when used in _defaults. :param datetime timestamp: optional datetime value to use instead of the current date and time (must be a datetime, regular dates can't be converted between timezones.) :param dict context: the 'tz' key in the context should give the name of the User/Client timezone (otherwise UTC is used) :rtype: str """ today = timestamp or DT.datetime.now() context_today = None if context and context.get('tz'): tz_name = context['tz'] else: tz_name = model.pool.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz'] if tz_name: try: utc = pytz.timezone('UTC') context_tz = pytz.timezone(tz_name) utc_today = utc.localize(today, is_dst=False) # UTC = no DST context_today = utc_today.astimezone(context_tz) except Exception: _logger.debug("failed to compute context/client-specific today date, " "using the UTC value for `today`", exc_info=True) return (context_today or today).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)class datetime(_column): _type = 'datetime' @staticmethod def now(*args): """ Returns the current datetime in a format fit for being a default value to a ``datetime`` field. This method should be provided as is to the _defaults dict, it should not be called. """ return DT.datetime.now().strftime( tools.DEFAULT_SERVER_DATETIME_FORMAT) @staticmethod def context_timestamp(cr, uid, timestamp, context=None): """Returns the given timestamp converted to the client's timezone. This method is *not* meant for use as a _defaults initializer, because datetime fields are automatically converted upon display on client side. For _defaults you :meth:`fields.datetime.now` should be used instead. :param datetime timestamp: naive datetime value (expressed in UTC) to be converted to the client timezone :param dict context: the 'tz' key in the context should give the name of the User/Client timezone (otherwise UTC is used) :rtype: datetime :return: timestamp converted to timezone-aware datetime in context timezone """ assert isinstance(timestamp, DT.datetime), 'Datetime instance expected' if context and context.get('tz'): tz_name = context['tz'] else: registry = openerp.modules.registry.RegistryManager.get(cr.dbname) tz_name = registry.get('res.users').read(cr, SUPERUSER_ID, uid, ['tz'])['tz'] if tz_name: try: utc = pytz.timezone('UTC') context_tz = pytz.timezone(tz_name) utc_timestamp = utc.localize(timestamp, is_dst=False) # UTC = no DST return utc_timestamp.astimezone(context_tz) except Exception: _logger.debug("failed to compute context/client-specific timestamp, " "using the UTC value", exc_info=True) return timestamp
应用示例代码:
#自动获取日期对应的月份并保存
def _get_month(self, cr, uid, ids, field_name, arg, context=None): res = {}
if context is None: context = {} DATETIME_FORMAT = "%Y-%m-%d" for sale in self.browse(cr, uid, ids, context=context): saledate = datetime.datetime.strptime(sale.date, DATETIME_FORMAT) res[sale.id] = saledate.strftime('%Y') + '-' + saledate.strftime('%m') return res _columns={ 'name':fields.char(u'单号', size=64, select=True, required=True, readonly=True), 'date':fields.date(u'日期', select=True, required=True, readonly=True), 'month':fields.function(_get_month, method=True, type='char', size=10, string = u'月份', store=True, invisible=True), }_defaults={
'name': lambda obj, cr, uid, context: '/', 'date':fields.date.context_today, #'employee_id':_employee_get, 'state':'draft' }
#自动计算到期日期,按开卡日期加 年数*365 天
def _get_due_date(self, cr, uid, ids, field_name, arg, context=None): res = {}
if context is None: context = {} DATE_FORMAT = "%Y-%m-%d" for rec in self.browse(cr, uid, ids, context=context): category = rec.category if category: remaining_times=category.times_limit if rec.active_date: res[rec.id]=(datetime.datetime.strptime(rec.active_date, DATE_FORMAT) + datetime.timedelta(days=category.age_limit*365)).strftime(DATE_FORMAT) else: res[rec.id]=(datetime.date.today()+ datetime.timedelta(days=category.age_limit*365)).strftime(DATE_FORMAT) return res _columns={ "name":fields.char("卡号",size=64, required=True, readonly=True, states={'0':[('readonly',False)]}), "category":fields.many2one("dispatch.service_card_category","服务卡类型", required=True, readonly=True, states={'0':[('readonly',False)]}), 'age_limit':fields.related('category', 'age_limit', string=u'年限', type='float', readonly=True, store=True), "times_limit":fields.integer(u"初始次数", readonly=True), "customer":fields.many2one("dispatch.customer","客户",required=True, select=True, readonly=True, states={'0':[('readonly',False)]}), "remaining_times":fields.integer("剩余次数",required=True, readonly=True, states={'0':[('readonly',False)]}), "active_date":fields.date("开卡日期",required=True, readonly=True, states={'0':[('readonly',False)]}), 'due_date':fields.function(_get_due_date, method=True, type='date', string = u'到期日期', store=True), 'state': fields.selection([('0', u'未开卡'),('1', u'已开卡'),('2', u'已用完'),('3', u'已过期'),('4', u'已锁定')], u'状态',required=True, readonly=True), 'lock_note': fields.char(u'锁定原因', size=200, invisible=False, readonly=True, states={'1':[('readonly',False)], '4':[('readonly',False)]}), }# TODO: can be improved using resource calendar method
#计算日期间隔对应的天数 def _get_number_of_days(self, date_from, date_to): """Returns a float equals to the timedelta between two dates given as string."""DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
from_dt = datetime.datetime.strptime(date_from, DATETIME_FORMAT) to_dt = datetime.datetime.strptime(date_to, DATETIME_FORMAT) timedelta = to_dt - from_dt diff_day = timedelta.days + float(timedelta.seconds) / 86400 return diff_day #对象字段 _columns = { 'date_from': fields.datetime(u'起始日期',required=True, readonly=True, states={'draft':[('readonly',False)]}, select=True), 'date_to': fields.datetime(u'结束日期', readonly=True, states={'draft':[('readonly',False)]}), 'days': fields.float(u'天数', digits=(8, 2), readonly=True, states={'draft':[('readonly',False)]}), } #更改起始日期,自动计算请假天数 def onchange_date_from(self, cr, uid, ids, date_to, date_from): """ If there are no date set for date_to, automatically set one 8 hours later than the date_from. Also update the number_of_days. """ # date_to has to be greater than date_from if (date_from and date_to) and (date_from > date_to): raise osv.except_osv(_(u'警告!'),_(u'开始日期必须小于结束日期.'))result = {'value': {}}
# No date_to set so far: automatically compute one 8 hours later if date_from and not date_to: date_to_with_delta = datetime.datetime.strptime(date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT) + datetime.timedelta(hours=8) result['value']['date_to'] = str(date_to_with_delta)
# Compute and update the number of days
if (date_to and date_from) and (date_from <= date_to): diff_day = self._get_number_of_days(date_from, date_to) result['value']['days'] = round(math.floor(diff_day))+1 else: result['value']['days'] = 0return result
#更改结束日期,自动计算请假天数 def onchange_date_to(self, cr, uid, ids, date_to, date_from): """ Update the number_of_days. """ # date_to has to be greater than date_from if (date_from and date_to) and (date_from > date_to): raise osv.except_osv(_(u'警告!'),_(u'开始日期必须小于结束日期.'))result = {'value': {}}
# Compute and update the number of days
if (date_to and date_from) and (date_from <= date_to): diff_day = self._get_number_of_days(date_from, date_to) result['value']['days'] = round(math.floor(diff_day))+1 else: result['value']['days'] = 0return result