A feature-rich, multi-calendar scheduling application built in Java with support for GUI, interactive CLI, and headless scripting modes. Designed with clean MVC architecture and comprehensive testing (95% branch coverage, 97% mutation score).
- Multiple Calendars: Create and manage multiple calendars with unique names and timezones
- Flexible Event Creation: Single events, all-day events, and recurring event series
- Smart Recurring Events: Repeat on specific weekdays with customizable frequency or end date
- Advanced Editing: Edit single instances, future events, or entire series with automatic detachment logic
- Cross-Calendar Operations: Copy events between calendars with automatic timezone conversion
- Conflict Detection: Prevents duplicate bookings across calendars
- Multiple Export Formats: Export to CSV or iCal format (Google Calendar compatible)
- Timezone Support: Full IANA timezone database support with automatic conversions
- GUI Mode: Interactive graphical interface with monthly calendar view
- Interactive CLI: Text-based command-line interface for manual operation
- Headless Mode: Batch execution from script files for automation
Monthly calendar view with event management sidebar
Event creation dialog with recurring options
Manage multiple calendars with different timezones
- Java Development Kit (JDK) 11 or higher
- Gradle (wrapper included)
Clone the repository and build the JAR:
git clone https://github.com/teja1412-hub/calendar-application.git
cd calendar-application
./gradlew jarThe JAR file will be created in build/libs/calendar-1.0.jar
java -jar build/libs/calendar-1.0.jarOr simply double-click the JAR file.
java -jar build/libs/calendar-1.0.jar --mode interactivejava -jar build/libs/calendar-1.0.jar --mode headless res/commands.txtCreate a New Calendar:
- Click "New Calendar" button
- Enter calendar name
- Select timezone from dropdown (e.g., America/New_York)
- Click OK
Switch Between Calendars:
- Click "Switch Calendar" button
- Select desired calendar from list
- Click OK
- Current calendar name displays with unique color coding
Edit Calendar Properties:
- Click "Edit Calendar" button
- Choose property to edit (name or timezone)
- Enter/select new value
- Click "Save Changes"
Create a Single Event:
- Click on desired date in calendar grid
- Click "Create Event" in right sidebar
- Fill in event details:
- Subject (required)
- Start/End times (HH:mm format, 24-hour)
- Location (optional)
- Description (optional)
- Status (PUBLIC/PRIVATE)
- For all-day events, check "All-day event" checkbox
- Click "Create"
Create a Recurring Event:
- Click desired date β "Create Event"
- Fill in basic event information
- Check "Recurring event" checkbox
- Select weekdays: Sun, Mon, Tue, Wed, Thu, Fri, Sat
- Choose recurrence end condition:
- Repeat count: Enter number of occurrences
- Repeat until: Enter end date (YYYY-MM-DD)
- Click "Create"
Edit Events:
- Select date containing the event
- Click "Edit Events"
- Choose event from dropdown
- Modify desired fields
- For recurring events, select edit scope:
- "This event only": Affects single occurrence
- "This and future events": Affects from this date forward
- "All events in series": Affects entire series
- Click "Save Changes"
Delete Events:
- Select date β Click "Delete Event"
- Choose event from dropdown
- Select deletion scope (for recurring events)
- Confirm deletion
- Event is permanently removed
Month Navigation:
- "< Previous": Go to previous month
- "Next >": Go to next month
- "Today": Return to current month
Date Selection:
- Click any date to view its events in right sidebar
- Selected date highlighted with blue border
- Today's date has yellow background
# Create a calendar
create calendar --name Work --timezone America/New_York
# Select active calendar
use calendar --name Work
# Edit calendar properties
edit calendar --name Work --property name Office
edit calendar --name Work --property timezone America/Chicago# Single timed event
create event "Team Meeting" from 2025-05-05T10:00 to 2025-05-05T11:00
# All-day event
create event "Birthday Party" on 2025-05-15
# Recurring event (with count)
create event "Daily Standup" from 2025-05-05T09:00 to 2025-05-05T09:30 repeats MTWRF for 20 times
# Recurring event (until date)
create event "Weekly Review" from 2025-05-02T14:00 to 2025-05-02T15:00 repeats F until 2025-12-31
# Recurring all-day event
create event Gym on 2025-05-06 repeats MWF for 30 timesWeekday Codes:
- M = Monday, T = Tuesday, W = Wednesday, R = Thursday
- F = Friday, S = Saturday, U = Sunday
# Edit single event
edit event subject Meeting from 2025-05-05T10:00 to 2025-05-05T11:00 with "Sprint Planning"
# Edit from point forward in series
edit events location "Daily Standup" from 2025-05-12T09:00 with "Conference Room B"
# Edit entire series
edit series subject "Weekly Review" from 2025-05-02T14:00 with "Team Retrospective"Editable Properties:
subject,start,end,description,location,status
# Copy single event
copy event "Team Meeting" on 2025-05-05T10:00 --target Personal to 2025-05-06T14:00
# Copy all events on a date
copy events on 2025-05-05 --target Personal to 2025-05-10
# Copy events in date range
copy events between 2025-09-05 and 2025-12-18 --target Spring2026 to 2026-01-08Note: Times automatically convert between calendar timezones
# View events on specific date
print events on 2025-05-05
# View events in time range
print events from 2025-05-05T08:00 to 2025-05-10T18:00
# Check availability
show status on 2025-05-05T14:30
# Returns: Busy or Available# Export to CSV (Google Calendar compatible)
export cal work_calendar.csv
# Export to iCal format
export cal work_calendar.icalFormat automatically detected by file extension. Absolute path displayed after export.
exit$ java -jar build/libs/calendar-1.0.jar --mode interactive
Calendar started. Enter commands (type 'exit' to quit):
create calendar --name Work --timezone America/New_York
Calendar 'Work' created successfully with timezone America/New_York
use calendar --name Work
Now using calendar: Work
create event "Team Meeting" from 2025-05-05T10:00 to 2025-05-05T11:00
Event created successfully.
create event "Daily Standup" from 2025-05-05T09:00 to 2025-05-05T09:30 repeats MTWRF for 10 times
Event series created successfully with 10 events.
print events on 2025-05-05
Daily Standup starting on 2025-05-05 at 09:00 ending on 2025-05-05 at 09:30, Status: PUBLIC
Team Meeting starting on 2025-05-05 at 10:00 ending on 2025-05-05 at 11:00, Status: PUBLIC
export cal work_calendar.csv
Calendar exported successfully to: /absolute/path/exports/work_calendar.csv
exit
Calendar has been terminated.Built following MVC (Model-View-Controller) architecture with strategic design patterns:
- MVC Pattern: Clean separation between data model, user interface, and control logic
- Chain of Responsibility: CLI command validation pipeline
- Facade Pattern: Simplified export operations (CSV/iCal)
- Command Pattern: Undo functionality support
- Adapter Pattern: Multi-calendar and timezone abstraction
- Observer Pattern: View synchronization (GUI updates)
calendar-application/
βββ src/
β βββ main/
β β βββ java/
β β βββ CalendarRunner.java # Main entry point
β β βββ calendar/
β β βββ controller/ # Controllers for different modes
β β βββ model/ # Core business logic
β β βββ view/ # User interfaces
β βββ test/ # Comprehensive test suite
β βββ controller/ # Controller tests with mocks
β βββ model/ # Model unit tests
β βββ integration/ # Integration tests
βββ res/
β βββ commands.txt # Sample command script
β βββ invalid.txt # Invalid command examples
βββ exports/ # Generated export files
βββ build.gradle # Gradle build configuration
βββ README.md # This file
Event Storage:
- Primary:
Map<LocalDate, List<Event>>for efficient date-based lookups - Alternative Explored: TreeMap for O(log n) sorted operations
- Choice Rationale: Map provides O(1) average-case lookups for date queries, which represents the most common operation (viewing events on a specific date). While TreeMap offers O(log n) sorted iteration, the added complexity wasn't justified for our use case where date-based access patterns dominate.
Recurring Events:
- Series metadata stored separately with detachment tracking
- Individual instances generated on-demand
- Edit operations intelligently split series when start times change
Scalability Considerations: For production-scale deployment (10,000+ events), consider:
- Lazy loading: Generate recurring instances on-demand rather than pre-computing
- Index structures: B-tree or skip list for range queries
- Database backing: Replace in-memory storage with SQLite/PostgreSQL for persistence
- Caching layer: LRU cache for frequently accessed date ranges
(The test coverage excludes the view as we cannot test the GUI with automated testing.)
- Branch Coverage: 95%
- Mutation Score: 97% (PIT mutation testing)
- Test Cases: 600+ comprehensive tests
- Model Tests: Comprehensive unit tests for all business logic
- Controller Tests: Mock-based testing for user interaction flows
- Integration Tests: End-to-end command execution validation
- Edge Cases: Timezone conflicts, series mutations, calendar consistency
# Run all tests
./gradlew test
# Generate coverage report
./gradlew jacocoTestReport
# Run mutation testing
./gradlew pitestCoverage reports available in build/reports/jacoco/test/html/index.html
In CLI/Script Mode:
- Date:
YYYY-MM-DD(e.g., 2025-05-05) - DateTime:
YYYY-MM-DDTHH:mm(e.g., 2025-05-05T14:30) - Time: 24-hour format
In GUI Mode:
- Date fields:
YYYY-MM-DD - Time fields:
HH:mm(24-hour)
Uses Java's ZoneId with IANA timezone database:
- Americas:
America/New_York,America/Chicago,America/Los_Angeles - Europe:
Europe/London,Europe/Paris,Europe/Berlin - Asia:
Asia/Tokyo,Asia/Kolkata,Asia/Shanghai - And 500+ more...
- Unique Events: No two events can have identical subject, start time, and end time
- Calendar Names: Must be unique across all calendars
- Time Validation: End time must be after start time
- Recurring Events: Must occur on at least one weekday
- Series Integrity: Start time changes create new series (automatic detachment)
Exported CSV files follow Google Calendar import format and can be directly imported.
Verification:
- Export calendar:
export cal my_events.csv - Go to Google Calendar β Settings β Import & Export
- Select exported CSV file
- Events should appear in your Google Calendar
Standard iCalendar format (.ical) compatible with:
- Google Calendar
- Apple Calendar
- Outlook
- Any RFC 5545 compliant calendar application
# Create semester calendar
create calendar --name "Fall 2025" --timezone America/New_York
use calendar --name "Fall 2025"
# Add recurring lectures
create event "CS 5010 Lecture" from 2025-09-08T10:00 to 2025-09-08T11:30 repeats TR until 2025-12-18
# Copy to next semester
create calendar --name "Spring 2026" --timezone America/New_York
copy events between 2025-09-08 and 2025-12-18 --target "Spring 2026" to 2026-01-13# Create work calendar
create calendar --name Work --timezone America/Chicago
# Regular meetings
create event "Team Standup" from 2025-05-05T09:00 to 2025-05-05T09:30 repeats MTWRF for 60 times
# One-time events
create event "Quarterly Review" from 2025-06-15T14:00 to 2025-06-15T16:00# All-day events
create event "Vacation" on 2025-07-04
create event "Birthday" on 2025-08-15
# Recurring activities
create event "Yoga Class" from 2025-05-06T18:00 to 2025-05-06T19:00 repeats MW for 24 times- Single Responsibility: Each class has one well-defined purpose
- Open/Closed: Extensible through interfaces (export formats, view types)
- Liskov Substitution: Polymorphic view and controller implementations
- Interface Segregation: Focused interfaces for model, view, controller
- Dependency Inversion: Dependencies on abstractions, not concrete classes
The application handles complex recurring event scenarios:
Example:
# Create series
create event "Team Sync" from 2025-05-05T10:00 to 2025-05-05T11:00 repeats MW for 6 times
# Edit subject of May 12 event and all future β affects 4 events
edit events subject "Team Sync" from 2025-05-12T10:00 with "Project Sync"
# Edit start time of May 12 event forward β creates new series (detachment!)
edit events start "Project Sync" from 2025-05-12T10:00 with 2025-05-12T10:30
# Now May 5 and May 7 form one series (10:00 start time)
# May 12, 14, 19, 21 form another series (10:30 start time)Try this in Google Calendar to see the same behavior!
Graceful Error Management:
- Invalid command syntax β Descriptive error message
- Timezone conflicts β Clear explanation
- Duplicate events β Conflict prevention message
- Missing calendar context β Prompt to select calendar
- Invalid dates/times β Format guidance
GUI Validation:
- Form field validation before submission
- Disabled invalid options
- Clear error dialogs with actionable messages
| Command | Description | Example |
|---|---|---|
create calendar --name <name> --timezone <tz> |
Create new calendar | create calendar --name Work --timezone America/New_York |
use calendar --name <name> |
Set active calendar | use calendar --name Work |
edit calendar --name <name> --property <prop> <value> |
Edit calendar | edit calendar --name Work --property timezone America/Chicago |
| Command | Description |
|---|---|
create event <subject> from <datetime> to <datetime> |
Single timed event |
create event <subject> on <date> |
Single all-day event |
create event <subject> from <datetime> to <datetime> repeats <days> for <N> times |
Recurring with count |
create event <subject> from <datetime> to <datetime> repeats <days> until <date> |
Recurring until date |
create event <subject> on <date> repeats <days> for <N> times |
Recurring all-day (count) |
create event <subject> on <date> repeats <days> until <date> |
Recurring all-day (date) |
| Command | Scope | Description |
|---|---|---|
edit event <prop> <subject> from <dt> to <dt> with <value> |
Single instance | Edit one occurrence |
edit events <prop> <subject> from <dt> with <value> |
This and future | Edit from date forward |
edit series <prop> <subject> from <dt> with <value> |
Entire series | Edit all occurrences |
| Command | Description |
|---|---|
copy event <subject> on <datetime> --target <cal> to <datetime> |
Copy single event |
copy events on <date> --target <cal> to <date> |
Copy all events on date |
copy events between <date> and <date> --target <cal> to <date> |
Copy date range |
| Command | Description |
|---|---|
print events on <date> |
List events on date |
print events from <datetime> to <datetime> |
List events in range |
show status on <datetime> |
Check if busy/available |
export cal <filename.csv> |
Export to CSV |
export cal <filename.ical> |
Export to iCal |
exit |
Terminate application |
- Java 11+: Core language
- Swing: GUI framework (Java standard library)
- JUnit 5: Unit testing
- JaCoCo: Code coverage analysis
- PIT: Mutation testing
- Gradle: Build automation
- 49 classes across model, view, controller
- ~2,700 lines of production code
- 95% branch coverage
- 97% mutation score
- Zero FindBugs violations
IntelliJ IDEA / Eclipse:
- Import project as Gradle project
- Run
CalendarRunner.javawith arguments:- No args β GUI mode
--mode interactiveβ CLI mode--mode headless res/commands.txtβ Script mode
This was developed as a course project for CS 5010 - Programming Design Paradigm at Northeastern University.
- Code reviews before merging
- Test coverage maintained above 90%
- All features validated against Google Calendar compatibility
This project was created for educational purposes as part of Northeastern University's CS 5010 course.
- Course: CS 5010 - Programming Design Paradigm, Northeastern University
- Inspiration: Google Calendar, Apple Calendar
- Assignment Design: Northeastern University Khoury College faculty
Teja Vejandla
- Email: vejandla.03@gmail.com
- LinkedIn: linkedin.com/in/bhavya-teja-vejandla
- GitHub: github.com/tejahub-1412
The application implements sophisticated recurring event logic with automatic series detachment:
Scenario: User creates recurring "Standup" M/W/F, then changes start time for one instance.
Result:
- Original series: Events keeping 10:00 start time
- New series: Events with modified 10:30 start time
- Both series maintain their recurrence patterns independently
This matches Google Calendar's behavior and demonstrates complex state management.
Challenge: Display events correctly when copying between timezones
Solution:
- Store all events with associated timezone
- Convert on-the-fly when copying to different calendar
- Example: 2:00 PM EST β 11:00 AM PST (automatic conversion)
Implementation:
// Pseudocode
ZonedDateTime sourceTime = event.getStartTime();
ZonedDateTime targetTime = sourceTime.withZoneSameInstant(targetCalendar.getZoneId());Algorithm:
- Check for overlapping events on event creation/edit
- Compare: subject, start time, end time
- Prevent: Exact duplicates across all calendars
- Allow: Same subject at different times
Current Implementation:
Map<LocalDate, List<Event>>for event storage- O(1) average lookup by date
- O(n) iteration for date ranges
Scalability Considerations:
For 10,000+ events:
- TreeMap: O(log n) lookups, O(log n) range queries
- B-tree: Optimal for disk-based storage
- Database: PostgreSQL with proper indexing for production scale
Trade-offs:
| Structure | Lookup | Range Query | Memory | Best For |
|---|---|---|---|---|
| HashMap | O(1) | O(n) | Medium | Current use case |
| TreeMap | O(log n) | O(log n) | Medium | 1K-10K events |
| B-tree | O(log n) | O(log n) | Low | 10K+ events, disk-based |
| Database | O(log n) | O(log n) | Minimal | Production, persistence |
- In-memory only: Events lost on application exit (no persistence)
- Single user: No multi-user support or concurrent access
- No reminders: Notification system not implemented
- Limited views: Only monthly view (weekly/daily views not included)
- No attachments: Cannot attach files to events
- Event persistence (database or file storage)
- Weekly and daily calendar views
- Event reminders and notifications
- Event attachments and notes
- Search and filter functionality
- Event categories/tags with color coding
- Import from CSV/iCal
- Multi-user support with permissions
- Mobile-responsive web interface
- Integration with external calendars (Google Calendar API)
β If you found this project useful, please star the repository!
