Skip to content

Instantly share code, notes, and snippets.

@imcarvalho
Created October 21, 2025 11:28
Show Gist options
  • Select an option

  • Save imcarvalho/4bebaf6930932fe72e0ed6c8edc56c73 to your computer and use it in GitHub Desktop.

Select an option

Save imcarvalho/4bebaf6930932fe72e0ed6c8edc56c73 to your computer and use it in GitHub Desktop.
Vibe coded Python script to convert from Moodflow backups to Daylio. You'll need to unzip and base64 encode and decode the Daylio backup file.
#!/usr/bin/env python3
import json
from datetime import datetime
# Load existing Daylio backup
with open('daylio_work/formatted.json', 'r') as f:
daylio_data = json.load(f)
# Load moodflow data
with open('moodflow_backup_2025-10-14T21-25-12-179Z.json', 'r') as f:
moodflow_data = json.load(f)
# Get existing entries and VALIDATE them
existing_entries = daylio_data.get('dayEntries', [])
valid_existing = []
invalid_existing = []
for entry in existing_entries:
year = entry.get('year')
month = entry.get('month')
day = entry.get('day')
try:
# Validate date
if year and month and day:
dt = datetime(year, month, day)
valid_existing.append(entry)
else:
raise ValueError('Missing date fields')
except (ValueError, TypeError) as e:
invalid_existing.append(f"{year}-{month:02d}-{day:02d} (ID {entry.get('id')})")
print(f"Original backup: {len(existing_entries)} entries")
print(f" Valid: {len(valid_existing)}")
print(f" Invalid (skipped): {len(invalid_existing)}")
if invalid_existing:
print(f" Skipped dates: {', '.join(invalid_existing)}")
# Create a set of existing valid dates for quick lookup
existing_dates = set()
for entry in valid_existing:
date_key = (entry.get('year'), entry.get('month'), entry.get('day'))
existing_dates.add(date_key)
# Convert moodflow entries with validation
new_entries = []
invalid_moodflow = []
moods_data = moodflow_data.get('data', {}).get('moods', {})
for year_str, year_data in moods_data.items():
if not isinstance(year_data, dict):
continue
for month_str, month_data in year_data.items():
if not isinstance(month_data, dict):
continue
for day_str, day_data in month_data.items():
if not isinstance(day_data, dict):
continue
year = day_data.get("year")
month = day_data.get("month")
day = day_data.get("day")
date_key = (year, month, day)
# Skip if already exists
if date_key in existing_dates:
continue
# Validate date
try:
dt = datetime(year, month, day, 12, 0, 0)
# Convert to Unix timestamp in milliseconds
timestamp_ms = int(dt.timestamp() * 1000)
# Create Daylio entry
entry = {
"id": 0, # Will reassign later
"minute": 0,
"hour": 12,
"day": day,
"month": month,
"year": year,
"datetime": timestamp_ms,
"timeZoneOffset": 0, # UTC
"mood": day_data.get("avgRating", 3),
"note": "",
"note_title": "",
"tags": [],
"assets": [],
"isFavorite": False
}
new_entries.append(entry)
except (ValueError, TypeError) as e:
invalid_moodflow.append(f"{year}-{month:02d}-{day:02d}")
print(f"\nMoodflow data: {len(new_entries)} new valid entries")
if invalid_moodflow:
print(f" Invalid (skipped): {len(invalid_moodflow)}")
print(f" Skipped dates: {', '.join(invalid_moodflow)}")
# Merge valid entries only
all_entries = valid_existing + new_entries
# Sort by datetime (NEWEST FIRST)
all_entries.sort(key=lambda x: x.get('datetime', 0), reverse=True)
# Reassign IDs sequentially from 1
for idx, entry in enumerate(all_entries, start=1):
entry['id'] = idx
print(f"\n✓ Total VALID entries after merge: {len(all_entries)}")
print(f"✓ IDs reassigned from 1 to {len(all_entries)}")
# Update daylio data
daylio_data['dayEntries'] = all_entries
# Update metadata
if 'metadata' in daylio_data:
daylio_data['metadata']['number_of_entries'] = len(all_entries)
daylio_data['metadata']['created_at'] = int(datetime.now().timestamp() * 1000)
# Save
with open('daylio_work/merged_validated.json', 'w') as f:
json.dump(daylio_data, f, indent=2)
print(f"\n✓ Validated data saved to: daylio_work/merged_validated.json")
print(f"\nVerification:")
print(f" Newest: {all_entries[0]['year']}-{all_entries[0]['month']:02d}-{all_entries[0]['day']:02d} (ID {all_entries[0]['id']})")
print(f" Oldest: {all_entries[-1]['year']}-{all_entries[-1]['month']:02d}-{all_entries[-1]['day']:02d} (ID {all_entries[-1]['id']})")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment