I’ve implemented several demand planning integrations and this date validation issue trips up everyone initially. Here’s the complete solution addressing all three focus areas:
Date Format Validation:
The demand planning REST API requires dates in yyyy-MM-dd format (ISO 8601 date-only, no time component). However, format alone isn’t sufficient - dates must align with planning bucket boundaries. The error message “Invalid date format” is misleading; it actually means “date doesn’t match a valid planning bucket.”
Correct format:
"ForecastDate": "2025-06-02"
NOT: “2025-06-02T00:00:00Z” or “2025-06-02T00:00:00”
Forecast Data Integration:
Before uploading forecasts, you must understand your demand plan’s bucket configuration:
- Query the demand plan details:
GET /fscmRestApi/resources/11.13.18.05/demandPlans/{planId}
Response includes:
- BucketType: DAILY, WEEKLY, MONTHLY, or QUARTERLY
- BucketStartDay: For weekly buckets (1=Monday, 7=Sunday)
- CalendarCode: Gregorian or custom fiscal calendar
- PlanTimezone: The timezone for all plan dates
- Calculate valid bucket dates based on configuration:
- Weekly buckets: Use bucket start day (e.g., every Monday)
- Monthly buckets: Use first day of each month
- Quarterly buckets: Use first day of fiscal quarter
- Daily buckets: Any date is valid
- Align your forecast dates to these boundaries:
LocalDate forecastDate = LocalDate.of(2025, 6, 5); // Thursday
DayOfWeek bucketStartDay = DayOfWeek.MONDAY;
// Adjust to previous Monday for weekly bucket
while (forecastDate.getDayOfWeek() != bucketStartDay) {
forecastDate = forecastDate.minusDays(1);
}
// Result: 2025-06-02 (Monday)
REST API Error Handling:
Implement comprehensive validation before upload:
public boolean isValidForecastDate(LocalDate date, DemandPlan plan) {
if (plan.getBucketType().equals("WEEKLY")) {
return date.getDayOfWeek().getValue() == plan.getBucketStartDay();
} else if (plan.getBucketType().equals("MONTHLY")) {
return date.getDayOfMonth() == 1;
} else if (plan.getBucketType().equals("QUARTERLY")) {
return isQuarterStart(date, plan.getCalendar());
}
return true; // Daily buckets accept any date
}
When upload fails, parse the error response to identify problematic dates:
try {
uploadForecasts(forecastData);
} catch (APIException e) {
if (e.getMessage().contains("Invalid date format")) {
// Log the specific dates that failed
logInvalidDates(forecastData);
// Revalidate dates against bucket configuration
List<ForecastRecord> correctedData = alignDatesToBuckets(forecastData, demandPlan);
// Retry with corrected dates
uploadForecasts(correctedData);
}
}
Additional Considerations:
-
Timezone handling: All dates are interpreted in the plan’s configured timezone. If your source system uses a different timezone, convert dates appropriately. Don’t use UTC timestamps - the API expects date-only values in the plan’s timezone.
-
Bulk upload optimization: For 500+ items with 26 weeks each (13,000 data points), batch your uploads:
- Process 50-100 items per API call
- Include all 26 weekly forecasts per item in a single call
- This reduces API calls from 13,000 to ~100-200
-
Calendar alignment: If using custom fiscal calendars (4-4-5, 4-5-4, etc.), query the calendar definition first and calculate bucket dates based on fiscal periods, not standard week boundaries.
-
Validation endpoint: Use the plan validation endpoint before actual upload:
POST /fscmRestApi/resources/11.13.18.05/demandPlans/{planId}/validateForecasts
This checks date alignment without committing data, helping you catch errors before the full upload.
Working Example:
For your weekly bucket plan starting Monday, generate forecast dates like this:
LocalDate startDate = LocalDate.of(2025, 6, 2); // First Monday
List<String> forecastDates = new ArrayList<>();
for (int week = 0; week < 26; week++) {
forecastDates.add(startDate.plusWeeks(week).toString());
}
// Results: ["2025-06-02", "2025-06-09", "2025-06-16", ...]
This ensures all dates align with weekly bucket boundaries and will pass API validation.