Source code for arxiv.submission.schedule

"""
Policies for announcement scheduling.

Submissions to arXiv are normally made public on Sunday through Thursday, with
no announcements Friday or Saturday.

+-----------------------+----------------+------------------------------------+
| Received Between (ET) | Announced (ET) | Mailed                             |
+=======================+================+====================================+
| Mon 14:00 - Tue 14:00 | Tue 20:00      | Tuesday Night / Wednesday Morning  |
| Tue 14:00 - Wed 14:00 | Wed 20:00      | Wednesday Night / Thursday Morning |
| Wed 14:00 - Thu 14:00 | Thu 20:00      | Thursday Night / Friday Morning    |
| Thu 14:00 - Fri 14:00 | Sun 20:00      | Sunday Night / Monday Morning      |
| Fri 14:00 - Mon 14:00 | Mon 20:00      | Monday Night / Tuesday Morning     |
+-----------------------+----------------+------------------------------------+

"""

from typing import Optional
from datetime import datetime, timedelta
from enum import IntEnum
from pytz import timezone, UTC

ET = timezone('US/Eastern')

Weekdays = IntEnum('Weekdays', 'Mon Tue Wed Thu Fri Sat Sun', start=1)

ANNOUNCE_TIME = 20
FREEZE_TIME = 14

WINDOWS = [
    ((Weekdays.Fri - 7, 14), (Weekdays.Mon, 14), (Weekdays.Mon, 20)),
    ((Weekdays.Mon, 14), (Weekdays.Tue, 14), (Weekdays.Tue, 20)),
    ((Weekdays.Tue, 14), (Weekdays.Wed, 14), (Weekdays.Wed, 20)),
    ((Weekdays.Wed, 14), (Weekdays.Thu, 14), (Weekdays.Thu, 20)),
    ((Weekdays.Thu, 14), (Weekdays.Fri, 14), (Weekdays.Sun, 20)),
    ((Weekdays.Fri, 14), (Weekdays.Mon + 7, 14), (Weekdays.Mon + 7, 20)),
]


def _datetime(ref: datetime, isoweekday: int, hour: int) -> datetime:
    days_hence = isoweekday - ref.isoweekday()
    repl = dict(hour=hour, minute=0, second=0, microsecond=0)
    return (ref + timedelta(days=days_hence)).replace(**repl)


[docs]def next_announcement_time(ref: Optional[datetime] = None) -> datetime: """Get the datetime of the next announcement.""" if ref is None: ref = ET.localize(datetime.now()) else: ref = ref.astimezone(ET) for start, end, announce in WINDOWS: if _datetime(ref, *start) <= ref < _datetime(ref, *end): return _datetime(ref, *announce)
[docs]def next_freeze_time(ref: Optional[datetime] = None) -> datetime: """Get the datetime of the next freeze.""" if ref is None: ref = ET.localize(datetime.now()) else: ref = ref.astimezone(ET) for start, end, announce in WINDOWS: if _datetime(ref, *start) <= ref < _datetime(ref, *end): return _datetime(ref, *end)