I think of this as 'interleaving' rather than 'joining', and there is surely more than one result that might be desirable.
I dug out some old code that I think is is close to what you want. Also, even within the world of JSL there will be good and less good ways to get to where you want to be. So, as an alternative to Eric's approach, please see below. I'm sure it could be made more efficient, and that might be something others could like to take a crack at . . .
NamesDefaultToHere(1);
// Make some 'date' data in two tables
nf = 100;
vals = J(nf, 1, RandomInteger(DateDMY(1,1,2014), DateDMY(31,12,2014)));
dtFine = NewTable("Date and Times in 2014 - Fine",
NewColumn("Date", Numeric, Continuous,
Format( "ddMonyyyy h:m:s", 22, 0 ),
Input Format( "ddMonyyyy h:m:s", 0 ),
Values(vals)
)
);
nc = 10;
vals = J(nc, 1, RandomInteger(DateDMY(1,1,2014), DateDMY(31,12,2014)));
dtCoarse = NewTable("Date and Times in 2014 - Coarse",
NewColumn("Date", Numeric, Continuous,
Format( "ddMonyyyy h:m:s", 22, 0 ),
Input Format( "ddMonyyyy h:m:s", 0 ),
Values(vals)
),
NewColumn("Temperature", Numeric, Continuous, Formula(RandomNormal(18, 2)))
);
dtFine << Sort( By( :Date ), Order( Ascending ), ReplaceTable );
dtCoarse << Sort( By( :Date ), Order( Ascending ), ReplaceTable );
// ******************************************************************************************************
// Interleave the coarse data with the fine data
// ******************************************************************************************************
// Add the columns from dtCoarse to dtFine
Wait(3);
n = NCol(dtFine);
cols = dtCoarse << getColumnNames("String");
For(c=1, c<=NItems(cols), c++,
dtype = Column(dtCoarse, cols[c]) << getDataType;
mtype = Column(dtCoarse, cols[c]) << getModelingType;
addCol = Expr(dtFine << NewColumn(cols[c], dtype, mtype, formatTBD));
SubstituteInto(addCol, Expr(formatTBD), Column(dtCoarse, cols[c]) << getFormat);
addCol;
);
// ******************************************************************************************************
// The logic relies on the two tables being sorted in ascending order!
// ******************************************************************************************************
fineDT = Column(dtFine, "Date") << getValues;
coarseDT = Column(dtCoarse, "Date") << getValues;
if(
// No time in dtCoarse is later than the earliest time in dtFine, so insert values in the first row in the latter
Max(coarseDT) < Min(fineDT),
For(c=1, c<=NItems(cols), c++,
Column(dtFine, n+c)[1] = Column(dtCoarse, cols[c])[NRow(dtCoarse)];
),
// Else . . .
// pos will contain the positions of the rows in dtFine at which the values in dtCoarse should be inserted.
// (Note: If a value in pos is bigger than NRow(dtFine), no row is added to the latter and no error results).
pos = LocSorted(fineDT, coarseDT);
pos = pos + J(NRow(pos), 1, 1);
// Insert values in cells
For(p=1, p<=NRow(pos), p++,
For(c=1, c<=NItems(cols), c++,
Column(dtFine, n+c)[pos[p]] = Column(dtCoarse, cols[c])[p];
);
);
);