Schedules define when access is permitted through doors or areas. They are fundamental building blocks that connect to access levels, determining when cardholders can enter controlled spaces. Schedules can contain multiple time intervals and can optionally specify holiday exception types to activate during specific holidays.
| Concept | Description |
|---|---|
| ScheduleInfo | The main schedule object containing one or more time durations |
| ScheduleDurationItem | A single time window defining days, start time, and duration |
| DayMask | Bit mask representing days of the week when schedule is active |
| HolidayExceptions | Flag values (1-8) indicating which holiday types activate this schedule |
| IsAlways | Special flag for 24/7 access schedules |
The DayMask is a 7-bit value where each bit represents a day of the week:
| Bit Position | Day | Value |
|---|---|---|
| 0 | Sunday | 1 |
| 1 | Monday | 2 |
| 2 | Tuesday | 4 |
| 3 | Wednesday | 8 |
| 4 | Thursday | 16 |
| 5 | Friday | 32 |
| 6 | Saturday | 64 |
Common DayMask Values:
| Pattern | Binary | Value | Description |
|---|---|---|---|
| Weekdays | 0111110 |
62 | Monday through Friday |
| Weekend | 1000001 |
65 | Saturday and Sunday |
| All Days | 1111111 |
127 | Every day |
| Mon/Wed/Fri | 0101010 |
42 | Alternating weekdays |
| Single Day (Monday) | 0000010 |
2 | Monday only |
This creates a typical 9 AM to 5 PM, Monday through Friday schedule:
var standardSchedule = await client.AddScheduleAsync(currentInstance,
new ScheduleInfo
{
CommonName = "StandardBusinessHours",
ScheduleDurations = new ScheduleDurationItem[]
{
new ScheduleDurationItem
{
// DayMask 62 = Monday through Friday (binary: 0111110)
DayMask = 62,
// Start at 9:00 AM
StartingAt = new TimeSpan(9, 0, 0),
// Duration of 8 hours (ends at 5:00 PM)
Duration = TimeSpan.FromHours(8)
}
}
});
Console.WriteLine($"Created schedule: {standardSchedule.CommonName} (Key: {standardSchedule.Key})");
var alwaysAccessSchedule = await client.AddScheduleAsync(currentInstance,
new ScheduleInfo
{
CommonName = "24-7-Access",
IsAlways = true // Special flag for continuous access
});
// Split shift: 6 AM - 10 AM and 2 PM - 10 PM, weekdays only
var extendedSchedule = await client.AddScheduleAsync(currentInstance,
new ScheduleInfo
{
CommonName = "ExtendedHours",
ScheduleDurations = new ScheduleDurationItem[]
{
// Morning shift
new ScheduleDurationItem
{
DayMask = 62, // Weekdays
StartingAt = new TimeSpan(6, 0, 0), // 6:00 AM
Duration = TimeSpan.FromHours(4) // Until 10:00 AM
},
// Afternoon/Evening shift
new ScheduleDurationItem
{
DayMask = 62, // Weekdays
StartingAt = new TimeSpan(14, 0, 0), // 2:00 PM
Duration = TimeSpan.FromHours(8) // Until 10:00 PM
}
}
});
var weekendSchedule = await client.AddScheduleAsync(currentInstance,
new ScheduleInfo
{
CommonName = "WeekendOnly",
ScheduleDurations = new ScheduleDurationItem[]
{
new ScheduleDurationItem
{
DayMask = 65, // Saturday (64) + Sunday (1)
StartingAt = new TimeSpan(8, 0, 0),
Duration = TimeSpan.FromHours(12)
}
}
});
// Night shift from 10 PM to 6 AM - duration can cross midnight
var nightSchedule = await client.AddScheduleAsync(currentInstance,
new ScheduleInfo
{
CommonName = "NightShift",
ScheduleDurations = new ScheduleDurationItem[]
{
// Sunday through Thursday nights (10 PM to 6 AM)
new ScheduleDurationItem
{
DayMask = 31, // Sun-Thu (binary: 0011111)
StartingAt = new TimeSpan(22, 0, 0), // 10:00 PM
Duration = TimeSpan.FromHours(8) // 8 hours (crosses midnight to 6:00 AM)
}
}
});
Configure schedules to be active during specific holiday types:
// Get holiday types configuration to understand available types
var holidayTypes = await client.GetHolidayTypesConfigurationAsync(currentInstance);
// Create schedule that is active during holiday type 1 (e.g., Company Holidays)
var holidaySchedule = await client.AddScheduleAsync(currentInstance,
new ScheduleInfo
{
CommonName = "HolidayAccess",
ScheduleDurations = new ScheduleDurationItem[]
{
new ScheduleDurationItem
{
DayMask = 127, // All days
StartingAt = new TimeSpan(8, 0, 0), // 8:00 AM
Duration = TimeSpan.FromHours(4), // 4 hours
HolidayExceptions = 1 // Active on holidays marked as Type 1
}
}
});
Note:
HolidayExceptionsuses flag values (1, 2, 4, 8, 16, 32, 64, 128) corresponding to holiday types 1-8. Combine flags to apply to multiple types:HolidayExceptions = 3(types 1 and 2). When a holiday day matches the exception type, this schedule duration becomes active on that holiday.
// Get all schedules in the instance
var allSchedules = await client.GetSchedulesAsync(currentInstance);
foreach (var schedule in allSchedules)
{
Console.WriteLine($"Schedule: {schedule.CommonName}");
Console.WriteLine($" Always Active: {schedule.IsAlways}");
Console.WriteLine($" Duration Count: {schedule.ScheduleDurations?.Length ?? 0}");
if (schedule.ScheduleDurations != null)
{
foreach (var duration in schedule.ScheduleDurations)
{
Console.WriteLine($" Days: {duration.DayMask}, Start: {duration.StartingAt}, Length: {duration.Duration}");
}
}
}
// Get specific schedule by name
var specificSchedule = (await client.SearchAsync(currentInstance, "{\"_t_\": \"Schedule\", \"CommonName\":\"StandardBusinessHours\"}"))
.OfType<ScheduleInfo>().FirstOrDefault();
curl -X POST \
"https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/schedules" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"$type": "Feenics.Keep.WebApi.Model.ScheduleInfo, Feenics.Keep.WebApi.Model",
"CommonName": "StandardBusinessHours",
"ScheduleDurations": [
{
"$type": "Feenics.Keep.WebApi.Model.ScheduleDurationItem, Feenics.Keep.WebApi.Model",
"DayMask": 62,
"StartingAt": "09:00:00",
"Duration": "08:00:00"
}
]
}'
curl -X POST \
"https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/schedules" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"$type": "Feenics.Keep.WebApi.Model.ScheduleInfo, Feenics.Keep.WebApi.Model",
"CommonName": "AlwaysActive",
"IsAlways": true
}'
curl -X GET \
"https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/schedules" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
| Practice | Recommendation |
|---|---|
| Naming | Use descriptive names like “Weekday-9AM-5PM” for easy identification |
| Midnight Crossing | Durations can cross midnight - no need to split into separate items |
| Always Access | Use IsAlways = true for 24/7 instead of creating 127/24hr duration |
| Holiday Exceptions | Use HolidayExceptions flags (1-8) to activate schedules on specific holiday types |
| Testing | Verify DayMask calculations match intended days before deployment |
| Documentation | Add notes to schedules explaining their business purpose |
Use this helper method to calculate DayMask values:
public static int CalculateDayMask(
bool sunday = false,
bool monday = false,
bool tuesday = false,
bool wednesday = false,
bool thursday = false,
bool friday = false,
bool saturday = false)
{
int mask = 0;
if (sunday) mask |= 1;
if (monday) mask |= 2;
if (tuesday) mask |= 4;
if (wednesday) mask |= 8;
if (thursday) mask |= 16;
if (friday) mask |= 32;
if (saturday) mask |= 64;
return mask;
}
// Usage:
int weekdayMask = CalculateDayMask(
monday: true,
tuesday: true,
wednesday: true,
thursday: true,
friday: true
);
// Returns: 62
| Issue | Cause | Solution |
|---|---|---|
| Schedule not active | Wrong DayMask | Verify bit values match intended days |
| Access denied outside hours | StartingAt/Duration mismatch | Check time calculations, use 24-hour format |
| Schedule not active on holiday | HolidayExceptions not set | Set HolidayExceptions flag to match holiday type (1-8) |
| Overnight access failing | Duration too long or DayMask wrong | Verify duration crosses midnight correctly, check DayMask for active days |
| Schedule not found | Wrong instance | Verify currentInstance context |