diff --git a/sync.py b/sync.py index af06953..f959d16 100644 --- a/sync.py +++ b/sync.py @@ -74,6 +74,30 @@ def convert_to_pacific_time(date_str): return '' +def parse_local_date(date_str): + """Parse a date string that is already in local (Pacific) time as YYYY-MM-DD. + + Filevine date-picker fields store calendar dates as midnight UTC, but they + represent the user's local date. This function extracts just the date portion + without any timezone conversion. + + Args: + date_str (str): ISO 8601 date string (e.g., "2026-05-29T00:00:00Z") + + Returns: + str: Date formatted as YYYY-MM-DD, or empty string if input is empty + """ + if not date_str: + return '' + + try: + dt = datetime.fromisoformat(date_str.replace('Z', '+00:00')) + return dt.strftime('%Y-%m-%d') + except (ValueError, AttributeError) as e: + print(f"[WARN] Date parse failed for '{date_str}': {e}") + return '' + + def extract_domains_from_emails(emails: List[str]) -> List[str]: """Extract unique domains from a list of email addresses. @@ -212,30 +236,30 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine ), '') # Extract notice service and expiration dates - notice_service_date = convert_to_pacific_time(new_file_review.get("noticeServiceDate")) or '' - notice_expiration_date = convert_to_pacific_time(new_file_review.get("noticeExpirationDate")) or '' + notice_service_date = parse_local_date(new_file_review.get("noticeServiceDate")) or '' + notice_expiration_date = parse_local_date(new_file_review.get("noticeExpirationDate")) or '' # Extract daily rent damages daily_rent_damages = lease_info_np.get("dailyRentDamages") or dates_and_deadlines.get("dailyRentDamages") or '' # Extract default date - default_date = convert_to_pacific_time(dates_and_deadlines.get("defaultDate")) or '' - case_filed_date = convert_to_pacific_time(dates_and_deadlines.get("dateCaseFiled")) or '' + default_date = parse_local_date(dates_and_deadlines.get("defaultDate")) or '' + case_filed_date = parse_local_date(dates_and_deadlines.get("dateCaseFiled")) or '' # Extract motion hearing dates - demurrer_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("demurrerHearingDate")) or '' - motion_to_strike_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("mTSHearingDate")) or '' - motion_to_quash_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("mTQHearingDate")) or '' - other_motion_hearing_date = convert_to_pacific_time(dates_and_deadlines.get("otherMotion1HearingDate")) or '' + demurrer_hearing_date = parse_local_date(dates_and_deadlines.get("demurrerHearingDate")) or '' + motion_to_strike_hearing_date = parse_local_date(dates_and_deadlines.get("mTSHearingDate")) or '' + motion_to_quash_hearing_date = parse_local_date(dates_and_deadlines.get("mTQHearingDate")) or '' + other_motion_hearing_date = parse_local_date(dates_and_deadlines.get("otherMotion1HearingDate")) or '' # Extract MSC details - msc_date = convert_to_pacific_time(dates_and_deadlines.get("mSCDate")) or '' + msc_date = parse_local_date(dates_and_deadlines.get("mSCDate")) or '' msc_time = dates_and_deadlines.get("mSCTime") or '' # Time field, not converting msc_address = dates_and_deadlines.get("mSCAddress") or '' msc_div_dept_room = dates_and_deadlines.get("mSCDeptDiv") or '' # Extract trial details - trial_date = convert_to_pacific_time(dates_and_deadlines.get("trialDate")) or '' + trial_date = parse_local_date(dates_and_deadlines.get("trialDate")) or '' trial_time = dates_and_deadlines.get("trialTime") or '' # Time field, not converting trial_address = dates_and_deadlines.get("trialAddress") or '' trial_div_dept_room = dates_and_deadlines.get("trialDeptDivRoom") or '' @@ -244,16 +268,16 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine final_result = dates_and_deadlines.get("finalResultOfTrialMSCCa") or '' # Extract settlement details - date_of_settlement = convert_to_pacific_time(dates_and_deadlines.get("dateOfStipulation")) or '' + date_of_settlement = parse_local_date(dates_and_deadlines.get("dateOfStipulation")) or '' final_obligation = dates_and_deadlines.get("finalObligationUnderTheStip") or '' def_comply_stip = dates_and_deadlines.get("defendantsComplyWithStip") or '' # Extract judgment and writ details - judgment_date = convert_to_pacific_time(dates_and_deadlines.get("dateOfJudgment")) or '' - writ_issued_date = convert_to_pacific_time(dates_and_deadlines.get("writIssuedDate")) or '' + judgment_date = parse_local_date(dates_and_deadlines.get("dateOfJudgment")) or '' + writ_issued_date = parse_local_date(dates_and_deadlines.get("writIssuedDate")) or '' # Extract lockout and stay details - scheduled_lockout = convert_to_pacific_time(dates_and_deadlines.get("sheriffScheduledDate")) or '' + scheduled_lockout = parse_local_date(dates_and_deadlines.get("sheriffScheduledDate")) or '' oppose_stays = dates_and_deadlines.get("opposeStays") or '' # Extract premises safety and entry code @@ -261,7 +285,7 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine matter_gate_code = property_info.get("propertyEntryCodeOrInstructions") or '' # Extract possession recovered date - date_possession_recovered = convert_to_pacific_time(dates_and_deadlines.get("datePossessionRecovered")) or '' + date_possession_recovered = parse_local_date(dates_and_deadlines.get("datePossessionRecovered")) or '' # Extract attorney fees and costs attorney_fees = fees_and_costs.get("totalAttorneysFees") or '' @@ -274,7 +298,7 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine client=c.get("firstName", ""), matter_description=p.get("projectName", ""), defendant_1=defendant_one.get('fullName', 'Unknown'), - matter_open=convert_to_pacific_time(dates_and_deadlines.get("dateCaseFiled") or p.get("createdDate")), + matter_open=parse_local_date(dates_and_deadlines.get("dateCaseFiled") or p.get("createdDate")), notice_type=new_file_review.get("noticeType", '') or '', case_number=dates_and_deadlines.get('caseNumber', '') or '', premises_address=property_info.get("premisesAddressWithUnit", "") or '', @@ -317,11 +341,11 @@ def process_project(index: int, total: int, project_data: dict, client: Filevine attorney_fees=attorney_fees, costs=costs, documents_url=matter_overview.get('documentShareFolderURL', '') or '', - service_attempt_date_1=convert_to_pacific_time(next(iter(service_info), {}).get('serviceDate')), + service_attempt_date_1=parse_local_date(next(iter(service_info), {}).get('serviceDate')), contacts=cs, project_email_address=p.get("projectEmailAddress", ""), number=p.get("number", "") or matter_overview.get('matterNumber', ''), - incident_date=convert_to_pacific_time(p.get("incidentDate") or detail.get("incidentDate")), + incident_date=parse_local_date(p.get("incidentDate") or detail.get("incidentDate")), project_id=pid, project_name=p.get("projectName") or detail.get("projectName"), project_url=p.get("projectUrl") or detail.get("projectUrl"),