DEV Community

Dora
Dora

Posted on

Making Date-Based Content Reusable

Making Date-Based Content Reusable

Problem

Content with specific dates can't be reused.

Example: An exam with these dates:

  • Grading due: Jan 18, 2024
  • Appeal deadline: Jan 20, 2024
  • Confirmation due: Jan 22, 2024

Want to reuse this exam in July? You have to manually update every date.
Have 50 exams? Good luck.

Common Approaches (and why they fail)

1. Hard-coded dates

exam.grade_due = datetime(2024, 1, 18)
exam.appeal_deadline = datetime(2024, 1, 20)
Enter fullscreen mode Exit fullscreen mode
  • Can't reuse
  • Every instance needs manual date updates

2. Copy everything

july_exam = copy(jan_exam)
july_exam.grade_due = datetime(2024, 7, 18)
# Update 10+ date fields...
Enter fullscreen mode Exit fullscreen mode
  • Content duplication
  • Update original? Copies don't change
  • Maintenance nightmare

3. Templates with placeholders

exam.dates = "{{start_date}} + 3 days"
Enter fullscreen mode Exit fullscreen mode
  • Complex parsing
  • No type safety
  • Hard to query

Solution: Store offsets, calculate at runtime

Content layer: Relative dates (logic only)

class Exam(Model):
    title = CharField(max_length=255)
    description = TextField()

    grade_due_days = PositiveSmallIntegerField()
    appeal_deadline_days = PositiveSmallIntegerField()
    confirm_due_days = PositiveSmallIntegerField()

    def get_grading_date(self, access_date: AccessDate):
        access_end = access_date["end"]
        grade_due = access_end + timedelta(days=self.grade_due_days)
        appeal_deadline = grade_due + timedelta(days=self.appeal_deadline_days)
        confirm_due = appeal_deadline + timedelta(days=self.confirm_due_days)
        return GradingDate(
            grade_due=grade_due, 
            appeal_deadline=appeal_deadline, 
            confirm_due=confirm_due
        )
Enter fullscreen mode Exit fullscreen mode

Context layer: Base dates (when it's actually used)

class Course(Model):
    title = CharField(max_length=255)
    start = DateTimeField()
    end = DateTimeField()
    archive = DateTimeField()

class Enrollment(Model):
    user = ForeignKey(User, CASCADE)
    course = ForeignKey(Course, CASCADE)
    active = BooleanField(default=True)
    start = DateTimeField()  # Can override course dates
    end = DateTimeField()
    archive = DateTimeField()
Enter fullscreen mode Exit fullscreen mode

In real-world use:

  • Course provides base dates for all students
  • Enrollment can override for individual students (e.g., extended deadline)
  • Either can serve as context for date calculation

Usage: Calculate absolute dates at runtime

async def get_session(cls, *, exam_id: str, learner_id: str, context: str, access_date: AccessDate):
    exam = await Exam.objects.select_related("owner", "honor_code", "question_pool").aget(id=exam_id)
    session = SessionDict(
        access_date=access_date,
        grading_date=exam.get_grading_date(access_date),  # Calculated here
        step=LearningSessionStep.READY,
        exam=exam,
    )
    return session
Enter fullscreen mode Exit fullscreen mode

Why This Works

Single source of truth:

  • Exam defines logic: "grading due 3 days after exam ends"
  • Course/Enrollment defines dates: "this course runs Jan-Mar"
  • Calculation happens when needed

Reusability:

Same exam:
- January course: Grade due Jan 18
- July course: Grade due Jul 18
- September course: Grade due Sep 18
Enter fullscreen mode Exit fullscreen mode

No duplication. No manual updates.

Update logic once:
Change grade_due_days = 3 to grade_due_days = 5
→ Affects all courses using this exam
→ Each with their own dates

Example

Define exam once:

exam = Exam.objects.create(
    title="Final Exam",
    grade_due_days=3,
    appeal_deadline_days=2,
    confirm_due_days=1
)
Enter fullscreen mode Exit fullscreen mode

Use in multiple courses:

# January course
jan_course = Course(
    title="Spring 2024",
    start=datetime(2024, 1, 1),
    end=datetime(2024, 1, 15)
)
grading_date = exam.get_grading_date(jan_course)
# grade_due: Jan 18, appeal_deadline: Jan 20, confirm_due: Jan 21

# July course
jul_course = Course(
    title="Summer 2024",
    start=datetime(2024, 7, 1),
    end=datetime(2024, 7, 15)
)
grading_date = exam.get_grading_date(jul_course)
# grade_due: Jul 18, appeal_deadline: Jul 20, confirm_due: Jul 21
Enter fullscreen mode Exit fullscreen mode

Same exam. Different dates. No duplication.

Key Insight

Separate concerns:

  • Content: Logic (offsets, rules)
  • Context: Base dates (when it happens)
  • Runtime: Absolute dates (calculated)

This makes content date-independent and infinitely reusable.

The full implementation

https://github.com/cobel1024/minima

Top comments (0)