def age( dt: Optional[datetime], now: Optional[datetime] = None, add_direction: bool = True, date_threshold: Optional[Any] = None, ) -> str: """ :param dt: :class:`datetime<datetime>` instance to format :param now: :class:`datetime<datetime>` instance to compare to `dt` :param add_direction: if `True`, will add "in" or "ago" (example for `en` locale) to time difference `dt - now`, i.e "in 9 min." or " 9min. ago" :param date_threshold: above threshold, will use a formated date instead of elapsed time indication. Supported values: "day". """ # Fail silently for now XXX if not dt: return "" if not now: now = datetime.utcnow() locale = babel.get_locale() dt = utc_dt(dt) now = utc_dt(now) delta = dt - now if date_threshold is not None: dy, dw, dd = dt_cal = dt.isocalendar() ny, nw, nd = now_cal = now.isocalendar() if dt_cal != now_cal: # not same day remove_year = dy == ny date_fmt = locale.date_formats["long"].pattern time_fmt = locale.time_formats["short"].pattern fmt = locale.datetime_formats["medium"] if remove_year: date_fmt = date_fmt.replace("y", "").strip() # remove leading or trailing spaces, comma, etc... date_fmt = re.sub("^[^A-Za-z]*|[^A-Za-z]*$", "", date_fmt) fmt = fmt.format(time_fmt, date_fmt) return babel.format_datetime(dt, format=fmt) # don't use (flask.ext.)babel.format_timedelta: as of Flask-Babel 0.9 it # doesn't support "threshold" arg. return format_timedelta( delta, locale=locale, granularity="minute", threshold=0.9, add_direction=add_direction, )
def age(dt, now=None, add_direction=True, date_threshold=None): """ :param dt: :class:`datetime<datetime.datetime>` instance to format :param now: :class:`datetime<datetime.datetime>` instance to compare to `dt` :param add_direction: if `True`, will add "in" or "ago" (example for `en` locale) to time difference `dt - now`, i.e "in 9 min." or " 9min. ago" :param date_threshold: above threshold, will use a formated date instead of elapsed time indication. Supported values: "day". """ # Fail silently for now XXX if not dt: return "" if not now: now = datetime.datetime.utcnow() locale = babel.get_locale() dt = utc_dt(dt) now = utc_dt(now) delta = dt - now if date_threshold is not None: dy, dw, dd = dt_cal = dt.isocalendar() ny, nw, nd = now_cal = now.isocalendar() if dt_cal != now_cal: # not same day remove_year = dy == ny date_fmt = locale.date_formats["long"].pattern time_fmt = locale.time_formats["short"].pattern fmt = locale.datetime_formats["medium"] if remove_year: date_fmt = date_fmt.replace("y", "").strip() # remove leading or trailing spaces, comma, etc... date_fmt = re.sub("^[^A-Za-z]*|[^A-Za-z]*$", "", date_fmt) fmt = fmt.format(time_fmt, date_fmt) return babel.format_datetime(dt, format=fmt) # don't use (flask.ext.)babel.format_timedelta: as of Flask-Babel 0.9 it # doesn't support "threshold" arg. return format_timedelta( delta, locale=locale, granularity="minute", threshold=0.9, add_direction=add_direction, )
def process_formdata(self, valuelist: List[str]) -> None: if valuelist: date_str = " ".join(valuelist) locale = get_locale() date_fmt = locale.date_formats["short"] date_fmt = babel2datetime(date_fmt) date_fmt = date_fmt.replace("%B", "%m").replace( "%b", "%m") # force numerical months time_fmt = locale.time_formats["short"] time_fmt = babel2datetime(time_fmt) datetime_fmt = f"{date_fmt} | {time_fmt}" try: self.data = datetime.strptime(date_str, datetime_fmt) if not self.use_naive: tz = get_timezone() if self.data.tzinfo: self.data = self.data.astimezone(tz) else: self.data = tz.localize(self.data) # convert to UTC self.data = utc_dt(self.data) except ValueError: self.data = None raise ValueError(self.gettext("Not a valid datetime value"))
def process_formdata(self, valuelist): if valuelist: date_str = ' '.join(valuelist) locale = get_locale() date_fmt = locale.date_formats['short'] date_fmt = babel2datetime(date_fmt) date_fmt = date_fmt.replace('%B', '%m')\ .replace('%b', '%m') # force numerical months time_fmt = locale.time_formats['short'] time_fmt = babel2datetime(time_fmt) datetime_fmt = u'{} | {}'.format(date_fmt, time_fmt) try: self.data = datetime.datetime.strptime(date_str, datetime_fmt) if not self.use_naive: tz = get_timezone() if self.data.tzinfo: self.data = self.data.astimezone(tz) else: self.data = tz.localize(self.data) # convert to UTC self.data = utc_dt(self.data) except ValueError: self.data = None raise ValueError(self.gettext('Not a valid datetime value'))
def process_formdata(self, valuelist): if valuelist: date_str = " ".join(valuelist) locale = get_locale() date_fmt = locale.date_formats["short"] date_fmt = babel2datetime(date_fmt) date_fmt = date_fmt.replace("%B", "%m").replace( "%b", "%m" ) # force numerical months time_fmt = locale.time_formats["short"] time_fmt = babel2datetime(time_fmt) datetime_fmt = f"{date_fmt} | {time_fmt}" try: self.data = datetime.datetime.strptime(date_str, datetime_fmt) if not self.use_naive: tz = get_timezone() if self.data.tzinfo: self.data = self.data.astimezone(tz) else: self.data = tz.localize(self.data) # convert to UTC self.data = utc_dt(self.data) except ValueError: self.data = None raise ValueError(self.gettext("Not a valid datetime value"))
def set_cache_headers(self, response): if self.set_expire: response.cache_control.public = False response.cache_control.private = True response.cache_control.max_age = int( self.expire_offset.total_seconds()) response.expires = utc_dt(datetime.utcnow() + self.expire_offset)
def process_formdata(self, valuelist): if valuelist: date_str = ' '.join(valuelist) locale = get_locale() date_fmt = locale.date_formats['short'] date_fmt = babel2datetime(date_fmt) date_fmt = date_fmt \ .replace('%B', '%m') \ .replace('%b', '%m') # force numerical months time_fmt = locale.time_formats['short'] time_fmt = babel2datetime(time_fmt) datetime_fmt = u'{} | {}'.format(date_fmt, time_fmt) try: self.data = datetime.datetime.strptime(date_str, datetime_fmt) if not self.use_naive: tz = get_timezone() if self.data.tzinfo: self.data = self.data.astimezone(tz) else: self.data = tz.localize(self.data) # convert to UTC self.data = utc_dt(self.data) except ValueError: self.data = None raise ValueError(self.gettext('Not a valid datetime value'))
def after_populate_obj(self): obj_meta = self.obj.meta.setdefault('abilian.core.models.comment', {}) history = obj_meta.setdefault('history', []) history.append(dict(user_id=current_user.id, user=unicode(current_user), date=utc_dt(datetime.utcnow()).isoformat(),)) self.obj.meta.changed()
def set_cache_headers(self, response): """ """ if self.set_expire: response.cache_control.public = False response.cache_control.private = True response.cache_control.max_age = int(self.expire_offset.total_seconds()) response.expires = utc_dt(datetime.utcnow() + self.expire_offset)
def after_populate_obj(self): obj_meta = self.obj.meta.setdefault("abilian.core.models.comment", {}) history = obj_meta.setdefault("history", []) history.append({ "user_id": current_user.id, "user": text_type(current_user), "date": utc_dt(datetime.utcnow()).isoformat(), }) self.obj.meta.changed()
def process_data(self, value: datetime) -> None: if value is not None: if not value.tzinfo: if self.use_naive: value = get_timezone().localize(value) else: value = utc_dt(value) if not self.use_naive: value = value.astimezone(get_timezone()) super().process_data(value)
def process_data(self, value): if value is not None: if not value.tzinfo: if self.use_naive: value = get_timezone().localize(value) else: value = utc_dt(value) if not self.use_naive: value = value.astimezone(get_timezone()) super().process_data(value)
def after_populate_obj(self): obj_meta = self.obj.meta.setdefault("abilian.core.models.comment", {}) history = obj_meta.setdefault("history", []) history.append( { "user_id": current_user.id, "user": str(current_user), "date": utc_dt(datetime.utcnow()).isoformat(), } ) self.obj.meta.changed()
def datetimeparse(s): """Parse a string date time to a datetime object. Suitable for dates serialized with .isoformat() :return: None, or an aware datetime instance, tz=UTC. """ try: dt = dateutil.parser.parse(s) except ValueError: return None return utc_dt(dt)
def datetimeparse(s) -> Optional[datetime]: """Parse a string date time to a datetime object. Suitable for dates serialized with .isoformat() :return: None, or an aware datetime instance, tz=UTC. """ try: dt = dateutil.parser.parse(s) except ValueError: return None return utc_dt(dt)
def after_populate_obj(self): session = sa.orm.object_session(self.obj) uploads = current_app.extensions["uploads"] self.obj.body_html = self.message_body obj_meta = self.obj.meta.setdefault("abilian.sbe.forum", {}) history = obj_meta.setdefault("history", []) history.append( { "user_id": current_user.id, "user": str(current_user), "date": utc_dt(datetime.utcnow()).isoformat(), "reason": self.form.reason.data, } ) self.obj.meta["abilian.sbe.forum"] = obj_meta # trigger change for SA attachments_to_remove = [] for idx in self.attachments_to_remove: try: idx = int(idx) except ValueError: continue if idx > len(self.obj.attachments): continue attachments_to_remove.append(self.obj.attachments[idx]) for att in attachments_to_remove: session.delete(att) for handle in request.form.getlist("attachments"): fileobj = uploads.get_file(current_user, handle) if fileobj is None: continue meta = uploads.get_metadata(current_user, handle) name = meta.get("filename", handle) mimetype = meta.get("mimetype") if not isinstance(name, str): name = str(name, encoding="utf-8", errors="ignore") if not name: continue attachment = PostAttachment(name=name, post=self.obj) with fileobj.open("rb") as f: attachment.set_content(f.read(), mimetype) session.add(attachment)
def after_populate_obj(self): session = sa.orm.object_session(self.obj) uploads = current_app.extensions['uploads'] self.obj.body_html = self.message_body obj_meta = self.obj.meta.setdefault('abilian.sbe.forum', {}) history = obj_meta.setdefault('history', []) history.append( dict( user_id=current_user.id, user=text_type(current_user), date=utc_dt(datetime.utcnow()).isoformat(), reason=self.form.reason.data, )) self.obj.meta['abilian.sbe.forum'] = obj_meta # trigger change for SA attachments_to_remove = [] for idx in self.attachments_to_remove: try: idx = int(idx) except ValueError: continue if idx > len(self.obj.attachments): continue attachments_to_remove.append(self.obj.attachments[idx]) for att in attachments_to_remove: session.delete(att) for handle in request.form.getlist('attachments'): fileobj = uploads.get_file(current_user, handle) if fileobj is None: continue meta = uploads.get_metadata(current_user, handle) name = meta.get('filename', handle) mimetype = meta.get('mimetype') if not isinstance(name, text_type): name = text_type(name, encoding='utf-8', errors='ignore') if not name: continue attachment = PostAttachment(name=name, post=self.obj) with fileobj.open('rb') as f: attachment.set_content(f.read(), mimetype) session.add(attachment)
def after_populate_obj(self): session = sa.orm.object_session(self.obj) uploads = current_app.extensions["uploads"] self.obj.body_html = self.message_body obj_meta = self.obj.meta.setdefault("abilian.sbe.forum", {}) history = obj_meta.setdefault("history", []) history.append({ "user_id": current_user.id, "user": text_type(current_user), "date": utc_dt(datetime.utcnow()).isoformat(), "reason": self.form.reason.data, }) self.obj.meta["abilian.sbe.forum"] = obj_meta # trigger change for SA attachments_to_remove = [] for idx in self.attachments_to_remove: try: idx = int(idx) except ValueError: continue if idx > len(self.obj.attachments): continue attachments_to_remove.append(self.obj.attachments[idx]) for att in attachments_to_remove: session.delete(att) for handle in request.form.getlist("attachments"): fileobj = uploads.get_file(current_user, handle) if fileobj is None: continue meta = uploads.get_metadata(current_user, handle) name = meta.get("filename", handle) mimetype = meta.get("mimetype") if not isinstance(name, text_type): name = text_type(name, encoding="utf-8", errors="ignore") if not name: continue attachment = PostAttachment(name=name, post=self.obj) with fileobj.open("rb") as f: attachment.set_content(f.read(), mimetype) session.add(attachment)
def seconds_since_epoch(dt): if not dt: return 0 return int((utc_dt(dt) - EPOCH).total_seconds())