Source code: C++ Sun Tracking and Calculation Classes 🛠

C++ source code for calculating various sun position parameters based on the date and your location. Some of the parameters calculated include the sunset time, sunrise time, sunlight duration, solar declination, zenith, elevation, etc.

This class may be useful for those who are looking to estimate various growing parameters when using sunlight as the main source of light, to determine how much and how many hours of sunlight you’ll receive at any point in time, to calculate the angle of the sun for solar panels, etc…

By creating a wrapper, you can do all sorts of neat things.

I will be extending this class at some point to calculate the solar equinox and solstices and will likely add an additional class that utilizes this class for estimating the DLI from the sun.

This is for the DIY types that have some software background. Questions/comment are great but I’d like to ask forum members to avoid the “what’s this good for” type questions within this thread to avoid clutter.

This class utilizes the constants header file (Constants.h) presented in the thread : Source code: C++ Temperature Conversion and Vapor Pressure Deficit Classes 🛠 and is built using C++11 and the boost libraries.

Edit: Fixed an error with the true solar time calculation.
Edit: Added sunset time. Corrected true solar time calculation for midnight.

//
// sun.cpp
// Version timestamp: 9-26-2018, 10:36 PM
//
// Attribution : Copyright (c) 2018 Northern_Loki (sha256::6F290BF833967127BE26C92C8F6B1C1A3949C55A7EABCEF3ECC785CD2D38D30D)
// License is granted under the Creative Commons Attribution-ShareAlike 4.0 International.  https://creativecommons.org/licenses/by-sa/4.0/
//

/* Based on the calculation methods per NOAA at https://www.esrl.noaa.gov/gmd/grad/solcalc/ */
/* This is a bit more complicated but is also a relatively accurate calculation method in comparision to some of the short cut algorithms. */

# include "sun.h"

sun::sun()
{

}

/* Constructor with user supplied latitude and longitude of the observor's position. Time is derived from the local */
/* system time and timezone. These must be correctly set in order to retreive accurate results. It will adjust for daylight savings time. */
sun::sun(const double &latitude, const double &longitude)
{
	/* Initialize the timezone. */
	tzset();

	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = "undefined";
	this->zone_time = NULL;
    
	/* No date/time provided, use the current system time. */
	this->utc_time = boost::posix_time::second_clock::universal_time();
	this->local_time = boost::posix_time::second_clock::local_time();
    
	set_julian(std::chrono::system_clock::now().time_since_epoch() / std::chrono::seconds(1));
    
	this->perform_solar_calculations();
}

sun::sun(std::string name, const double &latitude, const double &longitude)
{
	/* Initialize the timezone. */
	tzset();

	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = NULL;
    
	/* No date/time provided, use the current system time. */
	this->utc_time = boost::posix_time::second_clock::universal_time();
	this->local_time = boost::posix_time::second_clock::local_time();
    
	set_julian(std::chrono::system_clock::now().time_since_epoch() / std::chrono::seconds(1));
    
	this->perform_solar_calculations();
}

/* Constructor with user supplied latitude and longitude along with the date, time, and timezone of the observor's position,  */
/* This will adjust for daylight savings time depending on the user's timezone. */
sun::sun(const double &latitude, const double &longitude, std::tm &timeinfo)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = "undefined";
	this->zone_time = NULL;
    
	strncpy(this->timezone, timeinfo.tm_zone, 0x05);
	set_julian(std::mktime(&timeinfo));
    
	this->perform_solar_calculations();
}

/* Constructor with user supplied latitude and longitude along with the date, time, and timezone of the observor's position,  */
/* This will adjust for daylight savings time depending on the user's timezone. */
sun::sun(std::string name, const double &latitude, const double &longitude, std::tm &timeinfo)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = NULL;
    
	strncpy(this->timezone, timeinfo.tm_zone, 0x05);
	set_julian(std::mktime(&timeinfo));
    
	this->perform_solar_calculations();
}

sun::sun(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo)
{
	using namespace date;
	using namespace std;
	using namespace std::chrono;
    
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = &timeinfo;
    
	int current_year = (date::year_month_day{ date::floor<date::days>(timeinfo.get_local_time()) }.year() - 0_y).count();
    
	int year = current_year;

	set_julian(timeinfo);
    
	this->perform_solar_calculations();
}

sun::~sun()
{
}

void sun::set_julian(unsigned long epoch)
{
	this->time_epoch = epoch;
	this->julian = calculate_julian_time(this->time_epoch, true);
	this->julian_century = calculate_julian_century(this->julian);
}

void sun::set_julian(zoned_sun_time &timeinfo)
{
	this->julian = calculate_julian_time(timeinfo, true);
	this->julian_century = calculate_julian_century(this->julian);
}

void sun::set(const double &latitude, const double &longitude, std::tm &timeinfo)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = "undefined";
	this->zone_time = NULL;
    
	strncpy(this->timezone, timeinfo.tm_zone, 0x05);
	set_julian(std::mktime(&timeinfo));

	this->perform_solar_calculations();
}

void sun::set(std::string name, const double &latitude, const double &longitude, std::tm &timeinfo)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = NULL;
    
	strncpy(this->timezone, timeinfo.tm_zone, 0x05);
	set_julian(std::mktime(&timeinfo));
    
	this->perform_solar_calculations();
}

void sun::set(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = &timeinfo;
    
	set_julian(timeinfo);
    
	this->perform_solar_calculations();
}

void sun::set(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo, bool irrad)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = &timeinfo;
    
	set_julian(timeinfo);
    
	this->perform_solar_calculations();
}

void sun::operator()(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = &timeinfo;
    
	set_julian(timeinfo);
    
	this->perform_solar_calculations();
}

void sun::operator()(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo, bool irrad)
{
	this->observer_latitude = latitude;
	this->observer_longitude = longitude;
	this->name = name;
	this->zone_time = &timeinfo;
    
	set_julian(timeinfo);
    
	this->perform_solar_calculations();
}


void sun::perform_solar_calculations()
{
	/* Perform the calculations. */
	/* All of this to get the sunrise and sunset times, phew :) */
	this->geom_mean_longitude = calculate_mean_geom_longitude(this->julian_century);
	this->geom_mean_anomoly = calculate_mean_geom_anomoly(this->julian_century);
	this->eccentric_earth_orbit = calculate_eccentric_earth_orbit(this->julian_century);
	this->sun_center = calculate_center_of_sun(this->julian_century, this->geom_mean_anomoly);
	this->true_longitude = calculate_true_longitude(this->sun_center, this->geom_mean_longitude);
	this->true_anomoly = calculate_true_anomoly(this->sun_center, this->geom_mean_anomoly);
	this->rad_vector = calculate_rad_vector(this->true_anomoly, this->eccentric_earth_orbit);
	this->apparent_longitude = calculate_apparent_longitude(this->julian_century, this->true_longitude);
	this->mean_obliquity_ecliptic = calculate_mean_obliquity_ecliptic(this->julian_century);
	this->mean_obliquity_correction = calculate_obliquity_correction(this->julian_century, this->mean_obliquity_ecliptic);
	this->right_ascension = calculate_right_ascension(this->apparent_longitude, this->mean_obliquity_correction);
	this->declincation = calculate_declination(this->apparent_longitude, this->mean_obliquity_correction);
	this->EoT = calculate_EoT(this->mean_obliquity_correction, this->geom_mean_longitude, this->geom_mean_anomoly, this->eccentric_earth_orbit);
	this->sunrise_hour_angle = calculate_sunrise_hour_angle(this->observer_latitude, this->declincation);
	this->sunset_hour_angle = calculate_sunset_hour_angle(this->sunrise_hour_angle);
	this->solar_noon = calculate_solar_noon(this->observer_longitude, this->EoT);
	this->sunrise = calculate_sunrise_time(this->solar_noon, this->sunrise_hour_angle);
	this->sunset  = calculate_sunset_time(this->solar_noon, this->sunrise_hour_angle);

	/* Calculate other metrics */
	this->daylength = calculate_daylength(sunrise_hour_angle);
	/* True solar time / apparent solar time */
	this->time_midnight = time_since_midnight(this->zone_time);
	this->solar_time = calculate_solar_time(this->observer_longitude, this->time_midnight, this->EoT);
	/* Hour angle and zenith angle */
	this->hour_angle = calculate_hour_angle(this->solar_time);
	this->sec_z_inverse = calculate_inverse_secant_z(this->observer_latitude, this->declincation, this->hour_angle);
	this->zenith_angle = calculate_zenith_angle(this->sec_z_inverse);
	/* This is the true solar elevation without refraction. */
	this->solar_elevation = calculate_solar_elevation(this->zenith_angle);
	/* The following is what the observor would experience due to atmospheric refraction. Apparent elevation. */
	this->atmospheric_refraction = calculate_atmospheric_refraction(this->solar_elevation);
	this->solar_elevation_corrected = this->solar_elevation + this->atmospheric_refraction;
    
	this->solar_azimuth_angle = calculate_solar_azimuth_angle(this->observer_latitude, this->zenith_angle, this->hour_angle, this->declincation);
    
	/* Save some interesting values to easily utilized formats. */
	/* Any other values are accessible via class accessors. */
	this->sunrise_time = float_to_ptime(this->sunrise);
	this->sunset_time = float_to_ptime(this->sunset);
    
	/* Avoid performing the calculation at this point since it slows down the class construction. */
	//set_length_of_seasons(this->zone_time);
}

/* Reduced set of calculation for irradiation calculations. */
void sun::perform_solar_calculations_irrad()
{
	/* Placeholder. */
}

boost::posix_time::ptime sun::float_to_ptime(double value)
{
	boost::posix_time::ptime postime;
    
	tm test;
	test.tm_year = 2018 - 1900; 
	test.tm_mon = 1;
	test.tm_mday = 2;
    
	postime = boost::posix_time::from_time_t(this->time_epoch);
    
	value = value * 24.0;
	int hours = (int)(value);
	value -= hours;
	value = value * 60.0;
	int minutes = (int)(value);
	value -= minutes;
	value = value * 60.0;
	int seconds = (int)(value);
	value -= seconds;
	value = value * 1000.0;
	int milliseconds = (int)(value);
    
	test.tm_mday = postime.date().day();
	test.tm_year = postime.date().year() - 1900;
	test.tm_mon = postime.date().month() - 1;
	test.tm_yday = postime.date().day_of_year();
	test.tm_hour = hours;
	test.tm_min = minutes;
	test.tm_sec = seconds;
	test.tm_zone = this->timezone;
    
	postime = boost::posix_time::ptime_from_tm(test);
    
	return (postime);
}

/* Calculation of the solar angle between current solar angle and solar noon in radians. Input is the solar time in hours. Output is in degrees. */
double sun::calculate_hour_angle(double solar_time)
{
	double time = solar_time * (MINUTES_DAY);
    
	if ((time / 4.0) < 0)
	{
		hour_angle = (time / 4.0) + 180.0;
	}
	else
	{
		hour_angle = (time / 4.0) - 180.0;
	}
    
	return (hour_angle);
}


/* Julian centuries since Equinox J2000. J2000 is the julian date with 0 set to 12 noon January 1, 2000 */
/* this is due to the Precession of Equinoxes affect on the reference systems. The earth has a a precession */
/* "wobble" (nutation) with a cycle time of 26K years. J2000 references this effect as of the date of 1/1/2000. */
/* Verified */
double sun::calculate_julian_time(double time, bool unix_time)
{
	double julian;
    
	/* Calculate the Julian date */
	if (unix_time == true) 
	{
		julian = (time / SECONDS_DAY) + UNIX_JULIAN_EPOCH;
	}
	else 
	{
		julian = (time / SECONDS_DAY);
	}
    
	return (julian);
}

double sun::calculate_julian_time(zoned_sun_time &timeinfo, bool unix_time)
{
	this->time_epoch = (timeinfo.get_sys_time()).time_since_epoch().count() / 1000000000.0;
	double julian = calculate_julian_time(time_epoch, unix);
    
	return (julian);
}

/* Julian centuries since J2000 */
/* Verified */
double sun::calculate_julian_century(double julian)
{
	/* Calculate the Julian century */
	double julian_century = (julian - J2000) / (JULIAN_DAYS_CENTURY);
    
	return (julian_century);
}

/* Calculate the geometric mean longitude, degrees */
/* Verified */
double sun::calculate_mean_geom_longitude(double julian_century)
{
	double geom_mean = 280.46646 + julian_century*(36000.76983 + julian_century * 0.0003032);
	if (geom_mean < 0) geom_mean += 360;
	else if (geom_mean > 360) geom_mean = fmod(geom_mean, 360);  
    
	return (geom_mean);
}

/* Calculate the geometric anomoly, degrees */
/* Note, need to compare with "Calendrical Calculations: The Ultimate Edition", Reingold. NOAA factors differ. */
double sun::calculate_mean_geom_anomoly(double julian_century)
{
	double geom_anomoly = 357.52911 + julian_century * ((35999.05029) - (0.0001537 * julian_century));
    
	return (geom_anomoly);
}

/* Calculate the earth orbit eccentricity */
/* Note, need to compare with "Calendrical Calculations: The Ultimate Edition", Reingold. NOAA factors differ. */
double sun::calculate_eccentric_earth_orbit(double julian_century)
{
	double eccentric_earth = 0.016708634 - julian_century * (0.000042037 + 0.0000001267 * julian_century);
    
	return (eccentric_earth);
}

/* Calculate the center of the sun in degrees. */
double sun::calculate_center_of_sun(double julian_century, double geom_anomoly)
{
	double geom_anomoly_radians = TO_RADIAN(geom_anomoly);

	double sun_center = (sin(geom_anomoly_radians) * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century))) 
	    + (sin(geom_anomoly_radians * 2.0) * (0.019993 - 0.000101 * julian_century)) 
	    + (sin(geom_anomoly_radians * 3.0) * 0.000289);
    
	return (sun_center);
}

/* Calculate true longitude using center of sun angle adjustment. */
double sun::calculate_true_longitude(double sun_center, double geom_mean)
{
	double true_longitude = geom_mean + sun_center;
    
	return (true_longitude);
}

/* Calculate true anomoly using center of sun angle adjustment. */
double sun::calculate_true_anomoly(double sun_center, double geom_anomoly)
{
	double true_anomoly = geom_anomoly + sun_center;
    
	return (true_anomoly);
}

/* Calculate the distance to the sun. Results in astronomical units (AU) */
double sun::calculate_rad_vector(double true_anomoly, double eccentric_earth)
{
	double rad_vector = (1.000001018*(1.0 - eccentric_earth*eccentric_earth)) / (1.0 + eccentric_earth*cos(TO_RADIAN(true_anomoly)));
    
	return (rad_vector);
}

double sun::calculate_apparent_longitude(double julian_century, double true_longitude)
{
	double apparent_longitude = (true_longitude - 0.00569);
	apparent_longitude -= (0.00478*sin(TO_RADIAN(125.04 - (1934.136 * julian_century))));
    
	return (apparent_longitude);
}

/* Calculate the mean obliquity of the ecliptic. Return is in degrees. */
/* The equator is inclined at 23 degees, 26 minuts, and 21.448 seconds with respect to the earth's plane of rotation (the ecliptic) around the sun. */
/* This inclination (the obliquity) has a cycle that varies over 100K years a couple of degrees. We calculate the variation, here. */
/* Verified */
double sun::calculate_mean_obliquity_ecliptic(double julian_century)
{
	double mean_obliquity = 23.0 + (26.0 + ((21.448 - julian_century*(46.815 + julian_century*(0.00059 - julian_century * 0.001813)))) / 60.0) / 60.0;

	return (mean_obliquity);
}

/* Calculate the corrected mean obliquity of the ecliptic. Return is in degrees. */
double sun::calculate_obliquity_correction(double julian_century, double mean_obliquity)
{
	double obliquity_correction = mean_obliquity + 0.00256*cos(TO_RADIAN(125.04 - 1934.136*julian_century));
    
	return (obliquity_correction);
}

/* Calculate the right ascention. Return is in degrees. */
double sun::calculate_right_ascension(double apparent_longitude, double obliquity_correction)
{
	double right_ascension = TO_DEGREE(atan2(cos(TO_RADIAN(obliquity_correction))*sin(TO_RADIAN(apparent_longitude)), cos(TO_RADIAN(apparent_longitude))));
    
	return (right_ascension);
}

/* Calculate the solar declination. Return is in degrees. */
double sun::calculate_declination(double apparent_longitude, double obliquity_correction)
{
	double declination = TO_DEGREE(asin(sin(TO_RADIAN(obliquity_correction))*sin(TO_RADIAN(apparent_longitude))));
    
	return (declination);
}


/* Calculation of the approximate equation of time (correction) for the difference between mean and apparent solar time. */
/* Results in floating point minutes. */
double sun::calculate_EoT(double obliquity_correction, double geom_mean_longitude, double geom_mean_anomoly, double eccentric_earth_orbit)
{
	double tan_y = tan(TO_RADIAN(obliquity_correction / 2.0));
	double y = tan_y*tan_y;
	double geom_mean_longitude_radian = 2.0*TO_RADIAN(geom_mean_longitude);
	double geom_mean_anomoly_radian = TO_RADIAN(geom_mean_anomoly);
	double sin_anomoly = sin(geom_mean_anomoly_radian);
    
	double EoT1 = (y*sin(geom_mean_longitude_radian));
	double EoT2 = (2.0*eccentric_earth_orbit*sin_anomoly);
	double EoT3 = (4.0*eccentric_earth_orbit*y*sin_anomoly*cos(geom_mean_longitude_radian));
	double EoT4 = (0.5*y*y*sin(2*geom_mean_longitude_radian));
	double EoT5 = (1.25*eccentric_earth_orbit*eccentric_earth_orbit*sin(2.0*geom_mean_anomoly_radian));
    
	double EoT = EoT1 - EoT2 + EoT3 - EoT4 - EoT5;

	return (4.0*TO_DEGREE(EoT));
}


/* Calculation the local solar time of sunrise. Return is in floating point hours from noon. */
double sun::calculate_sunrise_time(double solar_noon, double hour_angle_sunrise)
{
	double sunset = solar_noon - ((hour_angle_sunrise * 4.0) / (MINUTES_DAY));
    
	return (sunset);
}

/* Calculation the local solar time of sunset. Return is in floating point hours from noon. */
double sun::calculate_sunset_time(double solar_noon, double hour_angle_sunrise)
{
	double sunset = solar_noon + ((hour_angle_sunrise * 4.0) / (MINUTES_DAY));
    
	return (sunset);
}


/* Calculate the number of hour of sunlight. Return is in floating point hours. */
double sun::calculate_daylength(double sunrise_hour_angle)
{
	return ((8.0 * sunrise_hour_angle) / (SECONDS_HOUR));
}

/* Calculation of the solar angle at sunrise. Output in degrees. */
double sun::calculate_sunrise_hour_angle(float latitude, double declination)
{	
	double sunrise = TO_DEGREE(acos(cos(TO_RADIAN(90.833)) / (cos(TO_RADIAN(latitude))*cos(TO_RADIAN(declination))) - tan(TO_RADIAN(latitude))*tan(TO_RADIAN(declination))));
    
	return (sunrise);
}

double sun::calculate_sunset_hour_angle(double sunrise_hour_angle)
{
	double sunset = (-1.0) * sunrise_hour_angle;
    
	return (sunset);
}

double sun::calculate_solar_noon(double observer_longitude, double EoT)
{
	double offset = get_offset_from_UTC(true);
    
	double solar_noon = ((720.0 - (4.0 *  observer_longitude) - EoT) + (offset * 60.0));
	solar_noon = solar_noon / (MINUTES_DAY);
    
	return (solar_noon);
}

/* Calculation of the solar time from the local time. Input is the local time in float days. Return is in floating point days. */
double sun::calculate_solar_time(double local_longitude, double time, double EoT)
{
	double offset = get_offset_from_UTC(true);
	double solar_time = (time * (MINUTES_DAY));
	solar_time += EoT;
	solar_time += (4.0*local_longitude);
	solar_time -= (60.0*offset);
    
	solar_time = fmod(solar_time, (MINUTES_DAY));
    
	return (solar_time / (MINUTES_DAY));
}

double sun::calculate_zenith_angle(double sec_z_inverse)
{
    
	double zenith = TO_DEGREE(acos(TO_RADIAN(sec_z_inverse)));
    
	return (zenith);
}

double sun::calculate_inverse_secant_z(double observer_latitude, double declincation, double hour_angle)
{    
	double secant_z_inverse = TO_DEGREE(sin(TO_RADIAN(observer_latitude))*sin(TO_RADIAN(declincation)) + cos(TO_RADIAN(observer_latitude))*cos(TO_RADIAN(declincation))*cos(TO_RADIAN(hour_angle)));
    
	return (secant_z_inverse);
}


double sun::calculate_solar_elevation(double zenith_angle)
{
	double elevation = 90.0 - zenith_angle;
    
	return (elevation);
}

/* Calculate the estimated refraction of light due to the atmospehere based on the solar elevation. This is an approximation. */
/* Zimmerman, John C.  1981.  Sun-pointing programs and their accuracy. */
double sun::calculate_atmospheric_refraction(double elevation)
{
	double refraction;
    
	if (elevation > 85.0)
	{
		refraction = 0.0;
	}
	else if (elevation > 5.0)
	{
		refraction = 58.1 / tan(TO_RADIAN(elevation)) - 0.07 / pow(tan(TO_RADIAN(elevation)), 3) + 0.000086 / pow(tan(TO_RADIAN(elevation)), 5);
	}
	else if (elevation > -0.575)
	{
		refraction = 1735.0 + elevation*(-518.2 + elevation*(103.4 + elevation*(-12.79 + elevation * 0.711)));
	}
	else
	{
		refraction = -20.772 / tan(TO_RADIAN(elevation));
	}
  
	return (refraction / (SECONDS_HOUR));
}

double sun::calculate_solar_azimuth_angle(double observer_latitude, double zenith, double hour_angle, double declination)
{
    
	double azimuth;
	if (hour_angle > 0)
	{
		azimuth = TO_DEGREE(acos(((sin(TO_RADIAN(observer_latitude))*cos(TO_RADIAN(zenith))) - sin(TO_RADIAN(declination))) / (cos(TO_RADIAN(observer_latitude))*sin(TO_RADIAN(zenith))))) + 180.0;
	}
	else
	{
		azimuth = 540.0 - TO_DEGREE(acos(((sin(TO_RADIAN(observer_latitude))*cos(TO_RADIAN(zenith))) - sin(TO_RADIAN(declination))) / (cos(TO_RADIAN(observer_latitude))*sin(TO_RADIAN(zenith)))));
	}
    
	if (azimuth > 360.0) azimuth = fmod(azimuth, 360.0);

	return (azimuth);
}


double sun::tune_soltice_equinox(double julian_estimate, double degrees)
{
	double correction = 0;
	double julian_century, geom_mean_longitude, geom_mean_anomoly, sun_center, true_longitude, apparent_longitude;
    
	do
	{
		/* Recalculate the sun position for each correction. */
		julian_century = calculate_julian_century(julian_estimate);
		geom_mean_longitude = calculate_mean_geom_longitude(julian_century);
		geom_mean_anomoly = calculate_mean_geom_anomoly(julian_century);
		sun_center = calculate_center_of_sun(julian_century, geom_mean_anomoly);
		true_longitude = calculate_true_longitude(sun_center, geom_mean_longitude);
		apparent_longitude = calculate_apparent_longitude(julian_century, true_longitude);
		correction = 58.0 * sin(TO_RADIAN(degrees - apparent_longitude));  
		julian_estimate += correction;
        
	} while (fabs(correction) > 0.00005); 
    
	return (julian_estimate);
    
}

/* Calculation of the earth nutation. Return is in degrees. */
double sun::calculate_earth_nutation(double julian_century)
{
	double c2 = julian_century * julian_century;
	double A = 124.90 - (1934.134 * julian_century) + (0.002063 * c2);
	double B = 201.11 + (72001.5377 * julian_century) + (0.00057 * c2);
    
	double nutation = TO_DEGREE(-0.004778 * sin(TO_RADIAN(A))) - (0.0003667 * sin(TO_RADIAN(B)));
    
	return (nutation);
}

void sun::calculate_soltice_equinox(zoned_sun_time *timeinfo, equinox_soltices_p solar_seasons)
{
	unsigned int year_int = ((date::year_month_day{ date::floor<date::days>(timeinfo->get_local_time()) }.year() - date::year{ 0 }).count());

	double julian_nw_equinox = 0;
	double julian_sw_equinox = 0;
	double julian_n_solstice = 0;
	double julian_s_solstice = 0;

	/* Astronomical Algorithms by Jean Meeus, (c) 1991 by Willman-Bell, Inc. */
	if (year_int <= 1000)
	{
		double year = (year_int) / 1000.0;
		double year2 = year*year;
		double year3 = year2*year;
		double year4 = year3*year;
		julian_nw_equinox = 1721139.29189 + 365242.13740*year + 0.06134*year2 + 0.00111*year3 - 0.00071*year4;
		julian_sw_equinox = 1721325.70455 + 365242.49558*year - 0.11677*year2 - 0.00297*year3 + 0.00074*year4;
		julian_n_solstice = 1721233.25401 + 365241.72562*year - 0.05323*year2 + 0.00907*year3 + 0.00025*year4;
		julian_s_solstice = 1721414.39987 + 365242.88257*year - 0.00769*year2 - 0.00933*year3 - 0.00006*year4;
	}
	else
	{
		double year = (year_int - 2000) / 1000.0;
		double year2 = year*year;
		double year3 = year2*year;
		double year4 = year3*year;
		julian_nw_equinox = 2451623.80984 + 365242.37404*year + 0.05169*year2 - 0.00411*year3 - 0.00057*year4;
		julian_sw_equinox = 2451810.21715 + 365242.01767*year - 0.11575*year2 + 0.00337*year3 + 0.00078*year4;
		julian_n_solstice = 2451716.56767 + 365241.62603*year + 0.00325*year2 + 0.00888*year3 - 0.00030*year4;
		julian_s_solstice = 2451900.05952 + 365242.74049*year - 0.06223*year2 - 0.00823*year3 + 0.00032*year4;
	}   

	julian_nw_equinox = tune_soltice_equinox(julian_nw_equinox, 0.0);
	julian_n_solstice = tune_soltice_equinox(julian_n_solstice, 90.0);
	julian_sw_equinox = tune_soltice_equinox(julian_sw_equinox, 180.0);
	julian_s_solstice = tune_soltice_equinox(julian_s_solstice, 270.0);
    
	solar_seasons->julian_nw_equinox = from_julian_date(julian_nw_equinox);
	solar_seasons->julian_sw_equinox = from_julian_date(julian_sw_equinox);
	solar_seasons->julian_n_solstice  = from_julian_date(julian_n_solstice);
	solar_seasons->julian_s_solstice  = from_julian_date(julian_s_solstice);
}

void sun::set_length_of_seasons(zoned_sun_time *timeinfo)
{
	equinox_soltices_t solar_seasons, solar_seasons_next; 
    
	/* Determine the solar seasons for this year.*/
	calculate_soltice_equinox(timeinfo, &solar_seasons);
    
	/* Determine the soloar seasons for the enxt year.*/
	std::chrono::duration<long long> tf(date::years{ 1 });
	auto next_year = timeinfo->get_local_time() + tf;
	zoned_sun_time timeinfo_next = date::make_zoned(timeinfo->get_time_zone()->name(), next_year);
	calculate_soltice_equinox(&timeinfo_next, &solar_seasons_next);
    
	bool northern_hemisphere = this->observer_latitude > 0 ? (true) : (false);
	if (northern_hemisphere)
	{
		this->seasons.LengthOfSpring = (solar_seasons.julian_n_solstice.get_sys_time() - solar_seasons.julian_nw_equinox.get_sys_time());
		this->seasons.LengthOfSummer = (solar_seasons.julian_sw_equinox.get_sys_time() - solar_seasons.julian_n_solstice.get_sys_time());
		this->seasons.LengthOfAutumn = (solar_seasons.julian_s_solstice.get_sys_time() - solar_seasons.julian_sw_equinox.get_sys_time());
		this->seasons.LengthOfWinter = (solar_seasons_next.julian_nw_equinox.get_sys_time() - solar_seasons.julian_s_solstice.get_sys_time());
	}
	else
	{
		this->seasons.LengthOfSpring = (solar_seasons.julian_s_solstice.get_sys_time() - solar_seasons.julian_sw_equinox.get_sys_time());
		this->seasons.LengthOfSummer = (solar_seasons_next.julian_nw_equinox.get_sys_time() - solar_seasons.julian_s_solstice.get_sys_time());
		this->seasons.LengthOfAutumn = (solar_seasons.julian_n_solstice.get_sys_time() - solar_seasons.julian_nw_equinox.get_sys_time());
		this->seasons.LengthOfWinter = (solar_seasons.julian_sw_equinox.get_sys_time() - solar_seasons.julian_n_solstice.get_sys_time());
	}	
    
	this->seasons.julian_nw_equinox = solar_seasons.julian_nw_equinox;
	this->seasons.julian_sw_equinox = solar_seasons.julian_sw_equinox;
	this->seasons.julian_n_solstice = solar_seasons.julian_n_solstice;
	this->seasons.julian_s_solstice = solar_seasons.julian_s_solstice;
    
}

double sun::time_since_midnight(zoned_sun_time *timeinfo)
{
	auto zero_hour = date::make_zoned(this->zone_time->get_time_zone()->name(), date::floor<date::days>(this->zone_time->get_local_time()));
	unsigned long zero_hour_epoch = zero_hour.get_local_time().time_since_epoch().count();
	unsigned long seconds_since_midnight_epoch = this->zone_time->get_local_time().time_since_epoch().count() / 1000000000;
	double time = (seconds_since_midnight_epoch - zero_hour_epoch);
	time = time / (SECONDS_DAY);
    
	if (time == 0) time = 1.0;
    
	return (time);
}

zoned_sun_time sun::from_julian_date(double julian)
{
	time_t timez;
	struct tm *p;
    
	/* Convert the julian time to unix time. */
	timez = (julian - UNIX_JULIAN_EPOCH)*SECONDS_DAY;
	p = gmtime(&timez);
    
	/* Daylight savings time. */
	std::string timezone_string = this->zone_time->get_time_zone()->name();
    
	/* Convert this to zone time, associated it to UTC then convert to the timezone of the user's operation. */
	date::sys_seconds t_sec = to_sys_time(*p);
	auto utc = date::make_zoned("UTC", t_sec);
	auto ny3 = date::make_zoned(timezone_string, utc);
    
	return (ny3);
}

date::local_seconds sun::to_local_time(std::tm const& t)
{
	using namespace date;
	using namespace std::chrono; 
	return (local_days{ year{ t.tm_year + 1900 } / (t.tm_mon + 1) / t.tm_mday } + hours{ t.tm_hour } + minutes{ t.tm_min } + seconds{ t.tm_sec });
}

date::sys_seconds sun::to_sys_time(std::tm const& t)
{
	using namespace date;
	using namespace std::chrono; 
	return (sys_days{ year{ t.tm_year + 1900 } / (t.tm_mon + 1) / t.tm_mday } + hours{ t.tm_hour } + minutes{ t.tm_min } + seconds{ t.tm_sec });
}

chrono_duration sun::fp_days_to_chrono(double fp_days)
{
	double hms_time = (fp_days * 24.0); 
	auto time = std::chrono::hours((unsigned int)hms_time);
    
	hms_time -= (unsigned int)hms_time;
	hms_time = hms_time * 60.0;
	auto time_hm = time + std::chrono::minutes((unsigned int)hms_time);
    
	hms_time -= (unsigned int)hms_time;
	hms_time = hms_time * 60.0;
	auto time_hms = time_hm + std::chrono::seconds((unsigned int)hms_time);
    
	fp_days -= (unsigned int)hms_time;
	hms_time = hms_time * 1000.0;
	auto time_hmsm = time_hms + std::chrono::milliseconds((unsigned int)hms_time);
    
	return (time_hms);
    
}



double sun::get_offset_from_UTC(bool adjust_for_dst)
{
	double offsetFromUTC;
    
	if (this->zone_time != NULL)
	{  
		auto info = this->zone_time->get_info();
		offsetFromUTC = info.offset.count() / (SECONDS_HOUR);
		if ((adjust_for_dst) && (info.save != std::chrono::minutes{ 0 })) offsetFromUTC = offsetFromUTC - 1;
	}
	else
	{
		time_t currtime;
		struct tm * timeinfo;

		/* Update the OS specific timezone information. */
		tzset();

		time(&currtime);
		timeinfo = gmtime(&currtime);
		time_t utc = mktime(timeinfo);
		timeinfo = localtime(&currtime);
		time_t local = mktime(timeinfo);
    
		// Get offset in hours from UTC
		offsetFromUTC = difftime(local, utc) / (SECONDS_HOUR);

		// Adjust for DST
		if((adjust_for_dst) && (timeinfo->tm_isdst))
		{
			offsetFromUTC += 1;
		}
	}

	return offsetFromUTC;
}

Header file is in the next post.

CC BY-SA 4.0

10 Likes

Header file for the above C++ class:

//
// sun.h
// Version timestamp: 9-26-2018, 10:36 PM
//
// Attribution : Copyright (c) 2018 Northern_Loki (sha256::6F290BF833967127BE26C92C8F6B1C1A3949C55A7EABCEF3ECC785CD2D38D30D)
// License is granted under the Creative Commons Attribution-ShareAlike 4.0 International.  https://creativecommons.org/licenses/by-sa/4.0/
//
# pragma once
# include <cstdlib>
# include <math.h>
# include <iostream>
# include <chrono>
# include <ctime>
# include <boost/date_time.hpp>
# include "Constants.h"
# include "tz.h"

typedef std::chrono::duration<long int, std::ratio<1l, 1000000000l>> time_duration;
typedef std::chrono::duration<long int, std::ratio<1l, 1l>> chrono_duration;
typedef date::zoned_time<time_duration> zoned_sun_time;
typedef std::chrono::time_point<date::local_t, chrono_duration> chrono_sun_time;

typedef struct
{
    zoned_sun_time julian_nw_equinox;
    zoned_sun_time julian_sw_equinox;
    zoned_sun_time julian_n_solstice;
    zoned_sun_time julian_s_solstice;
    time_duration LengthOfSpring;
    time_duration LengthOfSummer;
    time_duration LengthOfAutumn;
    time_duration LengthOfWinter;
} equinox_soltices_t, *equinox_soltices_p;


class sun_time
{
public:
    sun_time() {}
    ~sun_time() {}	
    
    bool *require_update;
    zoned_sun_time solar_time;
    zoned_sun_time operator()() {return solar_time;}
    zoned_sun_time operator=(zoned_sun_time rhs) {solar_time = rhs;}
    friend std::ostream& operator<<(std::ostream& lhs, const sun_time& rhs)
    {
        return (lhs << date::format("%b/%d/%Y %H:%M %Z", rhs.solar_time));
    }
};

class sun_duration
{
public:
    sun_duration() {}
    ~sun_duration() {}	

    time_duration solar_time;
    time_duration operator()() {return solar_time;}
    time_duration operator=(time_duration rhs) {solar_time = rhs;}
    friend std::ostream& operator<<(std::ostream& lhs, const sun_duration& rhs)
    {
        return (lhs << date::format("%H:%M", rhs.solar_time));
    }
};

class solar_seasons
{
public:
    solar_seasons() {}
    ~solar_seasons() {}
    
    sun_time julian_nw_equinox;
    sun_time julian_sw_equinox;
    sun_time julian_n_solstice;
    sun_time julian_s_solstice;
    sun_duration LengthOfSpring;
    sun_duration LengthOfSummer;
    sun_duration LengthOfAutumn;
    sun_duration LengthOfWinter;
};

class float_time
{
public:
    float_time() {}
    float_time(double value)
        : hour(value * 24.0)
        , minutes(((value * 24.0) - hour) * 60.0)
        , seconds(((value * 1440.0) - (hour * 24.0 + minutes)) * 60.0)
        , time(value) {}
    ~float_time() {}
    double operator()() {return time;}
    friend std::ostream& operator<<(std::ostream& lhs, const float_time& rhs)
    {
        return (lhs << rhs.hour << ":" << rhs.minutes << ":" << rhs.seconds << ":");
    }
    
    int hour;
    int minutes;
    int seconds;
    double time;
};

class length_of_day
{
public:
    length_of_day() {}
    length_of_day(double daylength)
        : hours(daylength * 60.0)
        , minutes(((daylength * 60.0) - hours) * 60.0)
        , seconds(((daylength * 3600.0) - (hours * 60.0 + minutes)) * 60.0)
        , length(daylength) {}
    ~length_of_day() {}
    double operator()() {return length;}
    friend std::ostream& operator<<(std::ostream& lhs, const length_of_day& rhs)
    {
        return (lhs << rhs.hours << " hours " << rhs.minutes << " minutes " << rhs.seconds << " seconds");
    }
    
    int hours;
    int minutes;
    int seconds;
    double length;
};

class sun
{
public:
    sun();
    sun(const double &latitude, const double &longitude);
    sun(std::string name, const double &latitude, const double &longitude);
    sun(const double &latitude, const double &longitude, std::tm &timeinfo);
    sun(std::string name, const double &latitude, const double &longitude, std::tm &timeinfo);
    sun(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo);
    ~sun();
    void set(const double &latitude, const double &longitude, std::tm &timeinfo);
    void set(std::string name, const double &latitude, const double &longitude, std::tm &timeinfo);
    void set(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo);
	void set(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo, bool irrad);
	void operator()(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo);
	void operator()(std::string name, const double &latitude, const double &longitude, zoned_sun_time &timeinfo, bool irrad);
    void perform_solar_calculations();
	void perform_solar_calculations_irrad();
    void set_julian(unsigned long epoch);
    void set_julian(zoned_sun_time &timeinfo);
    double calculate_julian_time(double time, bool unix_time);
    double calculate_julian_time(zoned_sun_time &timeinfo, bool unix_time);
    double calculate_julian_century(double julian);
    double calculate_mean_geom_longitude(double julian_century);
    double calculate_mean_geom_anomoly(double julian_century);
    double calculate_eccentric_earth_orbit(double julian_century);
    double calculate_center_of_sun(double julian_century, double geom_anomoly);
    double calculate_true_longitude(double geom_mean, double geom_anomoly);
    double calculate_true_anomoly(double sun_center, double geom_anomoly);
    double calculate_rad_vector(double true_anomoly, double eccentric_earth);
    double calculate_apparent_longitude(double julian_century, double true_longitude);
    double calculate_mean_obliquity_ecliptic(double julian_century);
    double calculate_obliquity_correction(double julian_century, double mean_obliquity_ecliptic);
    double calculate_right_ascension(double apparent_longitude, double obliquity_correction);
    double calculate_declination(double apparent_longitude, double obliquity_correction);
    double calculate_solar_noon(double observer_longitude, double EoT);
    double calculate_hour_angle(double solar_time);
	double calculate_solar_time(double local_longitude, double time, double EoT);
    double calculate_EoT(double obliquity_correction, double geom_mean_longitude, double geom_mean_anomoly, double eccentric_earth_orbit);
    double calculate_sunset_time(double solar_noon, double hour_angle_sunrise);
    double calculate_sunrise_time(double solar_noon, double hour_angle_sunrise);
    double calculate_sunrise_hour_angle(float latitude, double declination);
	double calculate_sunset_hour_angle(double sunrise_hour_angle);
    double calculate_daylength(double sunrise_hour_angle);
    double calculate_zenith_angle(double sec_z_inverse);
	double calculate_inverse_secant_z(double observer_latitude, double declincation, double hour_angle);
    double calculate_solar_elevation(double zenith_angle);
    double calculate_solar_azimuth_angle(double observer_latitude, double zenith, double hour_angle, double declination);
    double calculate_atmospheric_refraction(double elevation);
    double calculate_earth_nutation(double julian_century);
    double tune_soltice_equinox(double julian_estimate, double degrees);
    void calculate_soltice_equinox(zoned_sun_time *timeinfo, equinox_soltices_p solar_seasons);
    void set_length_of_seasons(zoned_sun_time *timeinfo);

	double time_since_midnight(zoned_sun_time *timeinfo);
    double get_offset_from_UTC(bool adjust_for_dst);
    boost::posix_time::ptime float_to_ptime(double value);
    zoned_sun_time from_julian_date(double julian);
    date::local_seconds to_local_time(std::tm const& t);
    date::sys_seconds to_sys_time(std::tm const& t);
	chrono_duration fp_days_to_chrono(double fp_days);
    
    std::string name;
    zoned_sun_time *zone_time;
    float observer_longitude;
    float observer_latitude;
    double julian;
    double julian_century;
    double geom_mean_longitude;
    double geom_mean_anomoly;
    double eccentric_earth_orbit;
    double sun_center;
    double true_longitude;
    double true_anomoly;
    double rad_vector;
    double apparent_longitude;
    double mean_obliquity_ecliptic;
    double mean_obliquity_correction;
    double right_ascension;
    double sunrise_hour_angle;
	double sunset_hour_angle;
    double hour_angle;
	double sec_z_inverse;
    double zenith_angle;
    double solar_elevation;
    double declincation;
    double solar_azimuth_angle;
    double atmospheric_refraction;
    double solar_elevation_corrected;
    double EoT;
    double solar_time;
    double solar_noon;
    double sunset;
	double time_midnight;
    boost::posix_time::ptime sunset_time;
    double sunrise;
    boost::posix_time::ptime sunrise_time;
    length_of_day daylength;
    solar_seasons seasons;
    
private:
    boost::posix_time::ptime local_time;
    boost::posix_time::ptime utc_time;
    std::time_t time_epoch;
    char timezone[8];
    boost::posix_time::time_duration timezone_offset; 
};

Example output:

--------------------------------------------------------------------------------------------------------------------------------------------
January
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2017-Dec-31 06:52:36    2017-Dec-31 17:01:31    10 hours 8 minutes 55 seconds   171.84    -81.84
Los Angeles     (34.052235,-118.243683) 2017-Dec-31 06:58:27    2017-Dec-31 16:53:54    9 hours 55 minutes 27 seconds   168.96    -78.96
Sydney          (-33.865143,151.209900) 2017-Dec-30 05:46:53    2017-Dec-30 20:09:06    14 hours 22 minutes 12 seconds  121.39    -31.39
New York        (40.730610,-73.935242)  2017-Dec-31 07:19:45    2017-Dec-31 16:38:01    9 hours 18 minutes 16 seconds   162.32    -72.32
Moscow          (55.751244,37.618423)   2017-Dec-31 08:59:20    2017-Dec-31 16:05:42    7 hours 6 minutes 21 seconds    146.78    -56.78
Chicago         (41.881832,-87.623177)  2017-Dec-31 07:18:08    2017-Dec-31 16:29:11    9 hours 11 minutes 3 seconds    161.12    -71.12
Auckland,NZ     (-36.848461,174.763336) 2017-Dec-30 06:04:21    2017-Dec-30 20:43:08    14 hours 38 minutes 46 seconds  116.88    -26.88

--------------------------------------------------------------------------------------------------------------------------------------------
February
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Jan-30 06:47:36    2018-Jan-30 17:27:19    10 hours 39 minutes 43 seconds  166.26    -76.26
Los Angeles     (34.052235,-118.243683) 2018-Jan-31 06:50:58    2018-Jan-31 17:21:46    10 hours 30 minutes 48 seconds  163.28    -73.28
Sydney          (-33.865143,151.209900) 2018-Jan-30 06:14:54    2018-Jan-30 20:01:58    13 hours 47 minutes 4 seconds   126.00    -36.00
New York        (40.730610,-73.935242)  2018-Jan-31 07:07:06    2018-Jan-31 17:11:09    10 hours 4 minutes 3 seconds    156.62    -66.62
Moscow          (55.751244,37.618423)   2018-Jan-30 08:26:26    2018-Jan-30 16:59:17    8 hours 32 minutes 50 seconds   140.92    -50.92
Chicago         (41.881832,-87.623177)  2018-Jan-31 07:04:22    2018-Jan-31 17:03:23    9 hours 59 minutes 0 seconds    155.52    -65.52
Auckland,NZ     (-36.848461,174.763336) 2018-Jan-30 06:34:33    2018-Jan-30 20:33:52    13 hours 59 minutes 18 seconds  121.15    -31.15

--------------------------------------------------------------------------------------------------------------------------------------------
March
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Mar-01 06:20:19    2018-Mar-01 17:52:29    11 hours 32 minutes 10 seconds  156.05    -66.05
Los Angeles     (34.052235,-118.243683) 2018-Mar-02 06:20:13    2018-Mar-02 17:49:56    11 hours 29 minutes 42 seconds  152.98    -62.98
Sydney          (-33.865143,151.209900) 2018-Mar-01 06:43:27    2018-Mar-01 19:31:23    12 hours 47 minutes 55 seconds  135.78    -45.78
New York        (40.730610,-73.935242)  2018-Mar-02 06:28:04    2018-Mar-02 17:47:40    11 hours 19 minutes 35 seconds  146.33    -56.33
Moscow          (55.751244,37.618423)   2018-Mar-02 07:18:39    2018-Mar-02 18:04:47    10 hours 46 minutes 8 seconds   130.78    -40.78
Chicago         (41.881832,-87.623177)  2018-Mar-02 06:23:42    2018-Mar-02 17:41:31    11 hours 17 minutes 49 seconds  145.21    -55.21
Auckland,NZ     (-36.848461,174.763336) 2018-Mar-01 07:06:40    2018-Mar-01 19:59:46    12 hours 53 minutes 5 seconds   130.66    -40.66

--------------------------------------------------------------------------------------------------------------------------------------------
April
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Apr-01 05:42:57    2018-Apr-01 18:13:08    12 hours 30 minutes 11 seconds  144.18    -54.18
Los Angeles     (34.052235,-118.243683) 2018-Apr-02 06:39:30    2018-Apr-02 19:13:50    12 hours 34 minutes 20 seconds  138.87    -48.87
Sydney          (-33.865143,151.209900) 2018-Apr-01 06:07:19    2018-Apr-01 17:50:48    11 hours 43 minutes 28 seconds  150.70    -60.70
New York        (40.730610,-73.935242)  2018-Apr-01 06:38:29    2018-Apr-01 19:20:27    12 hours 41 minutes 58 seconds  132.48    -42.48
Moscow          (55.751244,37.618423)   2018-Apr-01 05:59:43    2018-Apr-01 19:06:57    13 hours 7 minutes 13 seconds   119.18    -29.18
Chicago         (41.881832,-87.623177)  2018-Apr-01 06:32:24    2018-Apr-01 19:16:01    12 hours 43 minutes 37 seconds  131.70    -41.70
Auckland,NZ     (-36.848461,174.763336) 2018-Apr-01 06:34:19    2018-Apr-01 18:15:25    11 hours 41 minutes 6 seconds   147.19    -57.19

--------------------------------------------------------------------------------------------------------------------------------------------
May
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-May-01 05:09:03    2018-May-01 18:33:23    13 hours 24 minutes 19 seconds  133.47    -43.47
Los Angeles     (34.052235,-118.243683) 2018-May-02 06:02:40    2018-May-02 19:37:15    13 hours 34 minutes 35 seconds  129.10    -39.10
Sydney          (-33.865143,151.209900) 2018-May-01 06:30:07    2018-May-01 17:14:20    10 hours 44 minutes 13 seconds  161.28    -71.28
New York        (40.730610,-73.935242)  2018-May-02 05:53:08    2018-May-02 19:52:21    13 hours 59 minutes 12 seconds  122.54    -32.54
Moscow          (55.751244,37.618423)   2018-May-02 04:44:55    2018-May-02 20:08:12    15 hours 23 minutes 17 seconds  108.71    -18.71
Chicago         (41.881832,-87.623177)  2018-May-02 05:45:25    2018-May-02 19:49:33    14 hours 4 minutes 8 seconds    121.66    -31.66
Auckland,NZ     (-36.848461,174.763336) 2018-May-01 07:00:38    2018-May-01 17:35:24    10 hours 34 minutes 46 seconds  157.99    -67.99

--------------------------------------------------------------------------------------------------------------------------------------------
June
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Jun-01 04:50:45    2018-Jun-01 18:53:11    14 hours 2 minutes 26 seconds   126.68    -36.68
Los Angeles     (34.052235,-118.243683) 2018-Jun-01 05:42:30    2018-Jun-01 19:59:15    14 hours 16 minutes 45 seconds  122.52    -32.52
Sydney          (-33.865143,151.209900) 2018-Jun-01 06:51:33    2018-Jun-01 16:54:21    10 hours 2 minutes 48 seconds   168.08    -78.08
New York        (40.730610,-73.935242)  2018-Jun-01 05:26:34    2018-Jun-01 20:20:41    14 hours 54 minutes 7 seconds   115.92    -25.92
Moscow          (55.751244,37.618423)   2018-Jun-01 03:52:58    2018-Jun-01 21:01:46    17 hours 8 minutes 47 seconds   101.94    -11.94
Chicago         (41.881832,-87.623177)  2018-Jun-01 05:17:37    2018-Jun-01 20:19:08    15 hours 1 minutes 31 seconds   115.02    -25.02
Auckland,NZ     (-36.848461,174.763336) 2018-Jun-01 07:24:39    2018-Jun-01 17:12:47    9 hours 48 minutes 8 seconds    164.64    -74.64

--------------------------------------------------------------------------------------------------------------------------------------------
July
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Jul-01 04:53:49    2018-Jul-01 19:02:20    14 hours 8 minutes 30 seconds   125.70    -35.70
Los Angeles     (34.052235,-118.243683) 2018-Jul-02 05:45:39    2018-Jul-02 20:08:22    14 hours 22 minutes 42 seconds  121.33    -31.33
Sydney          (-33.865143,151.209900) 2018-Jul-01 07:00:59    2018-Jul-01 16:57:07    9 hours 56 minutes 8 seconds    169.21    -79.21
New York        (40.730610,-73.935242)  2018-Jul-02 05:28:40    2018-Jul-02 20:30:49    15 hours 2 minutes 9 seconds    114.74    -24.74
Moscow          (55.751244,37.618423)   2018-Jul-01 03:50:18    2018-Jul-01 21:16:39    17 hours 26 minutes 20 seconds  100.87    -10.87
Chicago         (41.881832,-87.623177)  2018-Jul-02 05:19:34    2018-Jul-02 20:29:26    15 hours 9 minutes 52 seconds   113.87    -23.87
Auckland,NZ     (-36.848461,174.763336) 2018-Jul-01 07:34:35    2018-Jul-01 17:15:04    9 hours 40 minutes 29 seconds   165.23    -75.23

--------------------------------------------------------------------------------------------------------------------------------------------
August
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Aug-01 05:10:48    2018-Aug-01 18:50:15    13 hours 39 minutes 27 seconds  130.74    -40.74
Los Angeles     (34.052235,-118.243683) 2018-Aug-01 06:04:35    2018-Aug-01 19:54:01    13 hours 49 minutes 25 seconds  126.18    -36.18
Sydney          (-33.865143,151.209900) 2018-Aug-01 06:47:46    2018-Aug-01 17:15:17    10 hours 27 minutes 31 seconds  164.19    -74.19
New York        (40.730610,-73.935242)  2018-Aug-01 05:52:37    2018-Aug-01 20:11:32    14 hours 18 minutes 55 seconds  119.61    -29.61
Moscow          (55.751244,37.618423)   2018-Aug-01 04:34:49    2018-Aug-01 20:36:56    16 hours 2 minutes 6 seconds    105.87    -15.87
Chicago         (41.881832,-87.623177)  2018-Aug-01 05:44:33    2018-Aug-01 20:09:06    14 hours 24 minutes 32 seconds  118.79    -28.79
Auckland,NZ     (-36.848461,174.763336) 2018-Jul-31 07:19:27    2018-Jul-31 17:35:11    10 hours 15 minutes 43 seconds  160.29    -70.29

--------------------------------------------------------------------------------------------------------------------------------------------
September
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Aug-31 05:29:41    2018-Aug-31 18:19:16    12 hours 49 minutes 34 seconds  140.24    -50.24
Los Angeles     (34.052235,-118.243683) 2018-Sep-01 06:26:23    2018-Sep-01 19:19:47    12 hours 53 minutes 23 seconds  135.83    -45.83
Sydney          (-33.865143,151.209900) 2018-Aug-31 06:14:34    2018-Aug-31 17:36:25    11 hours 21 minutes 50 seconds  154.66    -64.66
New York        (40.730610,-73.935242)  2018-Sep-01 06:22:25    2018-Sep-01 19:29:22    13 hours 6 minutes 57 seconds   129.27    -39.27
Moscow          (55.751244,37.618423)   2018-Aug-31 05:33:15    2018-Aug-31 19:26:17    13 hours 53 minutes 1 seconds   115.51    -25.51
Chicago         (41.881832,-87.623177)  2018-Sep-01 06:15:55    2018-Sep-01 19:25:20    13 hours 9 minutes 25 seconds   128.47    -38.47
Auckland,NZ     (-36.848461,174.763336) 2018-Aug-31 06:43:02    2018-Aug-31 17:59:35    11 hours 16 minutes 32 seconds  151.32    -61.32

--------------------------------------------------------------------------------------------------------------------------------------------
October
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Oct-01 05:47:37    2018-Oct-01 17:40:23    11 hours 52 minutes 45 seconds  151.63    -61.63
Los Angeles     (34.052235,-118.243683) 2018-Oct-01 06:47:37    2018-Oct-01 18:37:35    11 hours 49 minutes 58 seconds  147.73    -57.73
Sydney          (-33.865143,151.209900) 2018-Sep-30 05:32:45    2018-Sep-30 17:57:17    12 hours 24 minutes 31 seconds  142.90    -52.90
New York        (40.730610,-73.935242)  2018-Oct-01 06:52:22    2018-Oct-01 18:38:27    11 hours 46 minutes 5 seconds   141.19    -51.19
Moscow          (55.751244,37.618423)   2018-Oct-01 06:32:04    2018-Oct-01 18:06:31    11 hours 34 minutes 26 seconds  127.29    -37.29
Chicago         (41.881832,-87.623177)  2018-Oct-01 06:47:33    2018-Oct-01 18:32:45    11 hours 45 minutes 11 seconds  140.39    -50.39
Auckland,NZ     (-36.848461,174.763336) 2018-Sep-30 06:57:37    2018-Sep-30 19:24:05    12 hours 26 minutes 27 seconds  136.86    -46.86

--------------------------------------------------------------------------------------------------------------------------------------------
November
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Oct-31 06:08:53    2018-Oct-31 17:06:34    10 hours 57 minutes 41 seconds  162.20    -72.20
Los Angeles     (34.052235,-118.243683) 2018-Nov-01 07:12:12    2018-Nov-01 18:00:50    10 hours 48 minutes 37 seconds  158.66    -68.66
Sydney          (-33.865143,151.209900) 2018-Oct-31 05:55:37    2018-Oct-31 19:21:51    13 hours 26 minutes 13 seconds  131.12    -41.12
New York        (40.730610,-73.935242)  2018-Oct-31 07:25:29    2018-Oct-31 17:53:05    10 hours 27 minutes 36 seconds  152.25    -62.25
Moscow          (55.751244,37.618423)   2018-Oct-31 07:34:04    2018-Oct-31 16:52:05    9 hours 18 minutes 1 seconds    138.41    -48.41
Chicago         (41.881832,-87.623177)  2018-Nov-01 07:22:20    2018-Nov-01 17:45:44    10 hours 23 minutes 24 seconds  151.50    -61.50
Auckland,NZ     (-36.848461,174.763336) 2018-Oct-31 06:16:43    2018-Oct-31 19:52:19    13 hours 35 minutes 35 seconds  126.83    -36.83

--------------------------------------------------------------------------------------------------------------------------------------------
December
Location        Lat/Lon                 Sunrise                 Sunset                  Daylength                       Zenith    Elevation
Shanghai        (31.222219,121.458061)  2018-Nov-30 06:34:36    2018-Nov-30 16:51:19    10 hours 16 minutes 42 seconds  169.79    -79.79
Los Angeles     (34.052235,-118.243683) 2018-Dec-01 06:40:25    2018-Dec-01 16:43:37    10 hours 3 minutes 12 seconds   167.17    -77.17
Sydney          (-33.865143,151.209900) 2018-Nov-30 05:37:22    2018-Nov-30 19:50:26    14 hours 13 minutes 3 seconds   123.44    -33.44
New York        (40.730610,-73.935242)  2018-Dec-01 07:00:24    2018-Dec-01 16:29:03    9 hours 28 minutes 39 seconds   160.82    -70.82
Moscow          (55.751244,37.618423)   2018-Dec-01 08:34:19    2018-Dec-01 16:02:28    7 hours 28 minutes 8 seconds    145.85    -55.85
Chicago         (41.881832,-87.623177)  2018-Dec-01 06:58:35    2018-Dec-01 16:20:25    9 hours 21 minutes 50 seconds   159.50    -69.50
Auckland,NZ     (-36.848461,174.763336) 2018-Nov-30 05:55:30    2018-Nov-30 20:23:49    14 hours 28 minutes 18 seconds  119.18    -29.18

CC BY-SA 4.0

5 Likes

Example snippet of using this class to generate a graph of the daylight hours throughout the year:
edit: added min/max labels to chart generation.

/* Calculate and plot the daylight hours over the course of a year for New York, find the minimum and maximum daylight hours. */
zoned_sun_time newyork_area = date::make_zoned("America/New_York", date::local_time<date::days>{ date::January / 01 / 2018 });
std::cout << newyork_area << '\n' << std::endl;

sun sun_element_newyork;
double daymax, daymax_copy, daymin_copy, daymin = 1.0;

for (int day = 1; day < 365; day++)
    {
        /* Find the day with the maximum and minimum amounts of daylight. */
        sun_element_newyork.set("New York", 40.730610, -73.935242, newyork_area);
        double daylength = sun_element_newyork.daylength();
        
        if (daylength > daymax) daymax = daylength;
        if (daylength < daymin) daymin = daylength;
        
        newyork_area = newyork_area.get_local_time() + date::days{ 1 };
    }
    
    daymax_copy = daymax;
    daymax *= 60.0;
    int daymax_ceil = ceil(daymax);
    daymin_copy = daymin;
    daymin *= 60.0;
    int daymin_floor = floor(daymin);	
    double chart_x_quant = 96 / (daymax_ceil - daymin_floor);

    /* Plot the chart */
    int day_stride = 4;
    newyork_area = date::make_zoned("America/New_York", date::local_days{ date::January / 01 / 2018 });
    for (int day = 1; day < 365; day+=1)
    {
        sun_element_newyork.set("New York", 40.730610, -73.935242, newyork_area);
        double daylength = sun_element_newyork.daylength();
        
        if ((daylength) >= (daymax_copy) || (daylength) <= (daymin_copy) || (day % day_stride == 0))
        {
            if ((daylength * 60) > 14)
            {
                std::cout << date::format("%b %d %Y", newyork_area) << ": " << FG_GREEN << std::string(round(((daylength * 60.0) - daymin)*chart_x_quant), '*') << FG_DEFAULT;
            }
            else if ((daylength * 60) > 12)
            {
                std::cout << date::format("%b %d %Y", newyork_area) << ": " << FG_YELLOW << std::string(round(((daylength * 60.0) - daymin)*chart_x_quant), '*') << FG_DEFAULT;
            }
            else if ((daylength * 60) > 10)
            {
                std::cout << date::format("%b %d %Y", newyork_area) << ": " << FG_RED << std::string(round(((daylength * 60.0) - daymin)*chart_x_quant), '*') << FG_DEFAULT;
            }
            else
            {
                std::cout << date::format("%b %d %Y", newyork_area) << ": " << std::string(round(((daylength * 60.0) - daymin)*chart_x_quant), '*');
            }
        
            if ((daylength) >= (daymax_copy))
            {
                length_of_day length(daylength);
                std::cout << " <-max- " << length;
            }
            
            if ((daylength) <= (daymin_copy))
            {
                length_of_day length(daylength);
                std::cout << " <-min- " << length;
            }
        
            std::cout << std::endl;
        }	    
        
        newyork_area = newyork_area.get_local_time() + date::days{ 1 };
    }
    std::cout << std::endl;
    	

Outputs the following graph for the New York daylight hours over twelve months:

CC BY-SA 4.0

7 Likes

Thank you for this also! You pretty much did my work for me. I’ll barely have to do anything to make something once I get access

1 Like

Hopefully this will be helpful. Looking forward to hearing about your creations!

2 Likes

It will be very helpful in combination with the vpd code. together I plan on a automated system that controls the lighting, temperature, humidity, co2, airflow, and watering too if I feel like it. Creating a indoor garden that mimicks outside at a chosen area or time of your choosing.

3 Likes

Sweet :slight_smile: Could be fun to combine this with 3d models of trees etc. to simulate light hours for a guerilla grow. Unity might be a good choice for this - would just need to port it to C#.
We should make a stoned programmers group:) I’m working on a software tool for breeding atm.

1 Like

That would be pretty neat to see. Guerilla Grow, the game :smile:

I’ve haven’t started it yet, but I’ll be putting together a class for calculating DLI (unobstructed) and such that’ll hook into this class. There are some general estimates that can be determined for solar radiation. Along with the solar inclination information, we should be able to get reasonable real-time estimates.

I’m also working on some classes for calculating leaf energy balance equations. That leads to modeling transpiration or a plant with many leaves and the determination of growth conditions under different environmental conditions. Problem with part of that stuff is that there are a lot of hand-wavey guesstimates. Some of the model input are based entirely on empirical results such that it doesn’t necessarily translate from one location to another. The other problem, it’s complicated and mostly theoretical such that the models differ from place to place. But, maybe some insights will come of it, idk.

Should be “fairly” straight forward from c++. Like anything shared source code wise, there is always some tweaking needed. Date and time stuff might need some changes. But, in any case, most of the core equations are in there.

I’m running builds on an Nvidia Jetson TX1 embedded platform under Linux (ubuntu) and is the only physical platform I’ve tested it on at this point. But, it C++11 with libraries and nothing specifically tied to the platform itself.

Huh, dammit. I thought this was that place :laughing: Well, let’s try to get others with this DIY interest on-board. It looks like @OniTenshu has some interesting use cases in mind.

Yup, saw that thread. That’s really cool and am looking forward to seeing it! Definitely need tools like that.

1 Like

We can definitely work on combining our tools in a collection. If anyone here knows how we could make a universal app. We’d need someone who knows windows, iOS, Android/Linux, and whatever PlayStation uses again. We can make it a smart app or something that we could control when were away. If we used it to it’s fullest we could have a track system set up for watering, feeding, and foliar sprays. Even stationary lights, sprayers, and fans. Make a good old fashioned smart grow box. The only thing we’d need to be there for is training and pruning ideally. Keep the plants in a fully sealed environment completely controlled to a specific environment of our choosing. If we want to try to see how they would have grown during the Paleozoic era, then we could do that experiment LoL. Actually I really, want to do that now. think of the colors and size we’d see if it stayed alive

2 Likes

Hi @OniTenshu, cool ideas.

There is a lot that can be accomplished here from a big picture perspective. Whether it’s for a general/simple automated grow system, or perhaps some sort of experiment that needs to track/automatic specific variables. Or, maybe as you’ve noted, running some sort of recipe (would be cool to figure a good way to manage that).

On that note, here are some insights into my personal objectives at the moment:

I’m looking to take a bottom-up approach to producing code, a portion of which is shared here with more to come. Hardware specific details, from my viewpoint, are considered but avoided until later to avoid locking anything in. Code being released is meant to be somewhat agnostic to the how the data is collected or received. This’ll allow better re-usablility for those looking to DIY there own thing without having to be tied to a specific platform.

What I’m perceiving is that there are some ambitious folk DIYing their own automated systems. And, they have been for awhile. These folk collect whatever hardware they need and cobble together/write some code to get things up and running as quickly as possible. At some point, they’ll go back add additional features make things nice and so forth. Works great. But, for someone to replicate that system, they’ll essentially need to have an exact or very similar duplicate of the authors system. This may or may not meet all of their needs. Re-usability is low. And, depending on how the underlying code is structured, extensibility and scaling may also be difficult.

As a collection of classes placed into an architectural framework, a BSP (board support package) layer could provide the “translation” to various types of hardware and communication protocols. As new physical things come online, a BSP wrapper that can communicate with the “new” thing is generated while all of the underlying code would remain relatively stable. This minimizes the amount of “new” code that is needed in order to utilize the base framework.

For instance, I have a fancy set-up with lots of techno gadgets all running with custom code. I could share that code base but few would be able to utilize it without purchasing similar equipment. Or, spending a bunch of time modifying code. It would be a lot of work to do so.

So, my intent is to take a purposefully deliberate (and rather slow) path to generate pieces of (agnostic) code that others can utilize now while, at the same, eventually building a collection of source that will comprise of a framework. The overall framework could be utilized along with a BSP to ease the burden for the DIY custom systems while gaining the benefits of the underlying classes. Generated BSPs could target specific platforms, perhaps commercial open/or closed. Bolt-on on a UI/web interface and you’re off to the races. Hopefully, this will help others innovate on new systems and ideas. Maybe build something to share. Maybe something to sell. Who knows.

Just laying out my plans such that it might help with your project plans. None of what I’m saying here should dissuade you from pursuing your ideas, I think they’re great.

I’ll generate a diagram of what I have in mind since it might be easier to understand what I’m thinking graphically. Could use your thoughts on that once I have a chance to post it…

3 Likes

Sounds good to me. I was thinking more open source code TBH. I thought it was the plan

1 Like

Yes, this stuff is open under creative commons as far as I’m concerned.

2 Likes

I miss those days. The internet felt more honest

1 Like

Here is an example snippet for determining the dates of the equinox and solstice in a given year. The length of each season is also calculated although there is an error somewhere such the lengths when added are greater than the number of days in a year (which I’m looking into):

	/***************/
	zoned_sun_time shanghai1 = date::make_zoned("Asia/Shanghai", date::local_days{ date::January / 01 / 2018 });
	zoned_sun_time losangeles1 = date::make_zoned("America/Los_Angeles", date::local_days{ date::January / 01 / 2018 });
	zoned_sun_time sydney1 = date::make_zoned("Australia/Sydney", date::local_days{ date::January / 01 / 2018 });
	zoned_sun_time newyork1 = date::make_zoned("America/New_York", date::local_days{ date::January / 01 / 2018 });
	zoned_sun_time moscow1 = date::make_zoned("Europe/Moscow", date::local_days{ date::January / 01 / 2018 });
	zoned_sun_time chicago1 = date::make_zoned("America/Chicago", date::local_days{ date::January / 01 / 2018 });
	zoned_sun_time newzealand1 = date::make_zoned("Pacific/Auckland", date::local_days{ date::January / 01 / 2018 });
	
	std::vector<sun> sun_info_vec1;
	sun sun_element1("Shanghai", 31.22222, 121.45806, shanghai1);
	sun_info_vec1.push_back(sun_element1);
	sun_element1.set("Los Angeles", 34.052235, -118.243683, losangeles1);
	sun_info_vec1.push_back(sun_element1);
	sun_element1.set("Sydney", -33.865143, 151.209900, sydney1);
	sun_info_vec1.push_back(sun_element1);
	sun_element1.set("New York", 40.730610, -73.935242, newyork1);
	sun_info_vec1.push_back(sun_element1);
	sun_element1.set("Moscow", 55.751244, 37.618423, moscow1);
	sun_info_vec1.push_back(sun_element1);
	sun_element1.set("Chicago", 41.881832, -87.623177, chicago1);
	sun_info_vec1.push_back(sun_element1);
	sun_element1.set("Auckland,NZ", -36.848461, 174.763336, newzealand1);
	sun_info_vec1.push_back(sun_element1);
	
	std::cout << "--------------------------------------------------------------------------------------------------------------------------------------------" << std::endl;
	std::cout << boost::format("%-16s")  % "Location" <<  boost::format("%-32s")  % "Vernal Equinox" <<  boost::format("%-32s")  % "Summer Solstice" <<  boost::format("%-32s")  % "Fall Equinox" <<  boost::format("%-32s")  % "Winter Solstice";
	std::cout << std::endl;
		
	for (sun element : sun_info_vec1)
	{
		element.set_length_of_seasons(element.zone_time);
		std::string latlon = "(" + std::to_string(element.observer_latitude) + "," + std::to_string(element.observer_longitude) + ")";
		std::cout << boost::format("%-16s")  % element.name <<  boost::format("%-32s")  % element.seasons.julian_nw_equinox <<  boost::format("%-32s")  % element.seasons.julian_n_solstice <<  boost::format("%-32s")  % element.seasons.julian_sw_equinox <<  boost::format("%-32s")  % element.seasons.julian_s_solstice;
		std::cout << std::endl;
	}
	
	std::cout << "--------------------------------------------------------------------------------------------------------------------------------------------" << std::endl;
	std::cout << boost::format("%-16s")  % "Location" <<  boost::format("%-32s")  % "Length of Spring" <<  boost::format("%-32s")  % "Length of Summer" <<  boost::format("%-32s")  % "Length of Fall" <<  boost::format("%-32s")  % "Length of Winter";
	std::cout << std::endl;
		
	for (sun element : sun_info_vec1)
	{
		element.set_length_of_seasons(element.zone_time);
		std::string latlon = "(" + std::to_string(element.observer_latitude) + "," + std::to_string(element.observer_longitude) + ")";
		std::cout << boost::format("%-16s")  % element.name <<  boost::format("%-32s")  % element.seasons.LengthOfSpring <<  boost::format("%-32s")  % element.seasons.LengthOfSummer <<  boost::format("%-32s")  % element.seasons.LengthOfAutumn <<  boost::format("%-32s")  % element.seasons.LengthOfWinter;
		std::cout << std::endl;
	}
	sun_info_vec1.clear();
	std::cout << std::endl;

Produces the following:

--------------------------------------------------------------------------------------------------------------------------------------------
Location        Vernal Equinox                  Summer Solstice                 Fall Equinox                    Winter Solstice
Shanghai        Mar/21/2018 00:13 CST           Jun/21/2018 18:06 CST           Sep/23/2018 09:51 CST           Dec/22/2018 06:22 CST
Los Angeles     Mar/20/2018 09:13 PDT           Jun/21/2018 03:06 PDT           Sep/22/2018 18:51 PDT           Dec/21/2018 14:22 PST
Sydney          Mar/21/2018 03:13 AEDT          Jun/21/2018 20:06 AEST          Sep/23/2018 11:51 AEST          Dec/22/2018 09:22 AEDT
New York        Mar/20/2018 12:13 EDT           Jun/21/2018 06:06 EDT           Sep/22/2018 21:51 EDT           Dec/21/2018 17:22 EST
Moscow          Mar/20/2018 19:13 MSK           Jun/21/2018 13:06 MSK           Sep/23/2018 04:51 MSK           Dec/22/2018 01:22 MSK
Chicago         Mar/20/2018 11:13 CDT           Jun/21/2018 05:06 CDT           Sep/22/2018 20:51 CDT           Dec/21/2018 16:22 CST
Auckland,NZ     Mar/21/2018 05:13 NZDT          Jun/21/2018 22:06 NZST          Sep/23/2018 13:51 NZST          Dec/22/2018 11:22 NZDT
--------------------------------------------------------------------------------------------------------------------------------------------
Location        Length of Spring                Length of Summer                Length of Fall                  Length of Winter
Shanghai        2225:52                         2247:45                         2156:31                         2135:40
Los Angeles     2225:52                         2247:45                         2156:31                         2135:40
Sydney          2156:31                         2135:40                         2225:52                         2247:45
New York        2225:52                         2247:45                         2156:31                         2135:40
Moscow          2225:52                         2247:45                         2156:31                         2135:40
Chicago         2225:52                         2247:45                         2156:31                         2135:40
Auckland,NZ     2156:31                         2135:40                         2225:52                         2247:45

CC BY-SA 4.0

1 Like

Is it bad that c++ seems to look basic when shown? I swear it reminds me of the HTML code of websites or a css code. I can’t get the wrapping properly on my phone, but I got this once I have access to a PC again.

It’s bringing back memories of designing my website 12 years ago

1 Like

Yeah, you know, I have these feelings about C++ as a language. I’ve done more C development than C++ but figured I should dip my feet into C++ land. Some great features, abstraction, overloading, etc but as time goes on the language is becoming almost incomprehensible. Too me, it’s not clean looking anymore. Add templates and stuff and good luck trying to understand how some of the discombobulated libraries work.
The example snippets does seem to have a flavor of web development possibly because there is a bunch of print formatting. PHP like, maybe.

Wouldn’t this be more “universal” if it was in Java?

2 Likes

I was going to make a Java version actually.
If I can do both why not?

1 Like

C/C++ is perfectly universal and use-able. Disadvantage is that it has to built for the target platform, e.g. it’s not an interpreted language. Also the intent of scalability in certain instances may be a concern, see next paragraph. C++, like Java / Javascript, also has a variety of benefits some of which are significant. It’s a “it depends” question.

The main content on this class are the algorithms. These should be straight forward to port. If one would like to use these lower level classes directly as is, on a web-server for instance, anyone is free to contribute a port. Performance, depending, may become an issue for some of the iterative examples, for instance. idk. Also, it’s not necessarily difficult these days to use PHP wrappers,etc on the front end that interface to compiled libraries, as well. Depends on where you want the compute load to go to, the host or the client. Then, you’d need to consider the data side of things, etc…

Basically, I’m not a Java fan myself at this architectural level (and where I’m planning to go with this). I’m looking at “embedded” applications that act as a mote. Sensors interface to this mote, computation occurs on the mote, the external world can talk to the mote. The front-end to the mote can be anything and anywhere, Java for instance. In this type of scenario or similar, what usually changes on the app side is the front-end (which can be local or remote). The libraries on the “mote” usually become stable rather quickly and do not need to change as often. Also, there may be a point where the “universal” nature of Java / javascript suddenly becomes not so universal.

The use case is key to determining if Java would be a more sensible choice. I’m not your guy for that :wink:

1 Like

It’s just the idea that if I have a java script (js) file, I can use the same file on a “broken glass” system, a rotten fruit system, Linux, Android and i(suk)OS. A C file, I have to have a complete set of files, and while I can use it on all the above, I would have to compile and make separate files for each system.

I used to do some C+ back in the day (you know when we powered our computers by having a little dinosaur run on a treadmill) but even then I didn’t care for it.

1 Like